[
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the\n// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node\n{\n  \"name\": \"Node.js\",\n  \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:24\",\n  \"containerEnv\": {\n    \"HOST\": \"0.0.0.0\" // Let Nuxt listen on all interfaces, otherwise container port forwarding doesn't work.\n  },\n  \"postCreateCommand\": \"git config --global --add safe.directory ${containerWorkspaceFolder} && npm install\"\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "# see https://editorconfig.org/\n\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n\n[server/nginx-site-available]\nindent_size = 4\n"
  },
  {
    "path": ".gitattributes",
    "content": "# make JSON and Markdown files appear in GitHub language bar\n# see https://github.com/github/linguist#detectable\nfixtures/*/*.json linguist-detectable=true\nplugins/*/plugin.json linguist-detectable=true\nschemas/*.json linguist-detectable=true\n*.md linguist-detectable=true\n\n# enable automatic line ending handling\n# see https://rehansaeed.com/gitattributes-best-practices/\n* text=auto\n*.sh text eol=lf\n\n# explicitly set unix line endings for files that are checked by ESLint\n# see https://eslint.org/docs/rules/linebreak-style#using-this-rule-with-version-control-systems\n*.cjs text eol=lf\n*.js text eol=lf\n*.json text eol=lf\n*.md text eol=lf\n*.ts text eol=lf\n*.vue text eol=lf\n\n# mark agent lock files as generated and avoid manual conflict resolution\n# see https://github.github.com/gh-aw/reference/glossary/#workflow-lock-file-lockyml\n.github/workflows/*.lock.yml linguist-generated=true merge=ours\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/new-plugin.md",
    "content": "---\nname: New plugin\nabout: Open Fixture Library should have a plugin for this fixture format.\ntitle: Add [software / console name] Plugin\nlabels: new-plugin\nassignees: ''\n\n---\n\nXXXXX Please edit all lines that start with \"XXXXX\".  \nXXXXX Short description of the software / desk console using the fixture format.\n\n- **Link to the software / desk console website:**  \n  XXXXX\n- **Where can fixtures of this format be downloaded?**  \n  XXXXX\n- **What file type is the fixture format?**  \n  XXXXX Binary / XML / JSON / Unknown\n- **Does a schema / description / documentation of the format exist?**  \n  XXXXX Yes, here: XXXXX / No / Unknown\n- **Are there many fixtures of good quality in this format?**  \n  XXXXX Yes / No / Unknown\n- **Is there any existing work done to parse this format?**  \n  XXXXX Yes, here: XXXXX / No / Unknown\n"
  },
  {
    "path": ".github/aw/actions-lock.json",
    "content": "{\n  \"entries\": {\n    \"github/gh-aw-actions/setup@v0.68.3\": {\n      \"repo\": \"github/gh-aw-actions/setup\",\n      \"version\": \"v0.68.3\",\n      \"sha\": \"ba90f2186d7ad780ec640f364005fa24e797b360\"\n    }\n  }\n}\n"
  },
  {
    "path": ".github/dependabot.yaml",
    "content": "# See https://help.github.com/en/github/administering-a-repository/keeping-your-dependencies-updated-automatically\n\nversion: 2\nupdates:\n  - package-ecosystem: \"npm\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    labels:\n      - \"dependencies\"\n    groups:\n      eslint:\n        patterns:\n          - \"eslint\"\n          - \"@eslint/js\"\n    ignore:\n      - dependency-name: \"eslint-plugin-jsdoc\"\n        update-types:\n          - \"version-update:semver-patch\"\n          - \"version-update:semver-minor\"\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    labels:\n      - \"dependencies\"\n"
  },
  {
    "path": ".github/lighthouserc.json",
    "content": "{\n  \"ci\": {\n    \"collect\": {\n      \"startServerCommand\": \"npm run start\",\n      \"startServerReadyPattern\": \"Nuxt.js is ready.\",\n      \"startServerReadyTimeout\": 20000\n    }\n  }\n}\n"
  },
  {
    "path": ".github/workflows/external-links-checker.yaml",
    "content": "name: External Links Checker\non:\n  schedule:\n    - cron: '30 18 * * *' # everyday 18:30 UTC\n  workflow_dispatch:\njobs:\n  external-links:\n    name: Check external links\n    if: github.repository == 'OpenLightingProject/open-fixture-library'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6.0.2\n      - name: Setup Node.js v24\n        uses: actions/setup-node@v6.4.0\n        with:\n          node-version: 24\n          cache: 'npm'\n      - name: Install dependencies\n        run: npm ci\n      - name: Build\n        run: npm run build\n      - name: Check external links\n        run: node --tls-min-v1.0 tests/external-links.js\n        env:\n          GITHUB_USER_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          GITHUB_BROKEN_LINKS_ISSUE_NUMBER: 999\n          NODE_ENV: production\n      - name: Check Markdown Links in all files\n        uses: gaurav-nelson/github-action-markdown-link-check@v1\n        with:\n          use-verbose-mode: 'yes'\n"
  },
  {
    "path": ".github/workflows/fixture-metadata-triage.lock.yml",
    "content": "# gh-aw-metadata: {\"schema_version\":\"v3\",\"frontmatter_hash\":\"e3344764c91da961e68d011784f9ac52e21c60848ac0eef547ff7c18e0471ead\",\"compiler_version\":\"v0.68.3\",\"strict\":true,\"agent_id\":\"copilot\"}\n# gh-aw-manifest: {\"version\":1,\"secrets\":[\"COPILOT_GITHUB_TOKEN\",\"GH_AW_GITHUB_MCP_SERVER_TOKEN\",\"GH_AW_GITHUB_TOKEN\",\"GITHUB_TOKEN\"],\"actions\":[{\"repo\":\"actions/checkout\",\"sha\":\"de0fac2e4500dabe0009e67214ff5f5447ce83dd\",\"version\":\"v6.0.2\"},{\"repo\":\"actions/download-artifact\",\"sha\":\"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c\",\"version\":\"v8.0.1\"},{\"repo\":\"actions/github-script\",\"sha\":\"373c709c69115d41ff229c7e5df9f8788daa9553\",\"version\":\"v9\"},{\"repo\":\"actions/upload-artifact\",\"sha\":\"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a\",\"version\":\"v7.0.1\"},{\"repo\":\"github/gh-aw-actions/setup\",\"sha\":\"ba90f2186d7ad780ec640f364005fa24e797b360\",\"version\":\"v0.68.3\"}],\"containers\":[{\"image\":\"ghcr.io/github/gh-aw-firewall/agent:0.25.20\"},{\"image\":\"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20\"},{\"image\":\"ghcr.io/github/gh-aw-firewall/squid:0.25.20\"},{\"image\":\"ghcr.io/github/gh-aw-mcpg:v0.2.19\"},{\"image\":\"ghcr.io/github/github-mcp-server:v0.32.0\"},{\"image\":\"node:lts-alpine\"}]}\n#    ___                   _   _      \n#   / _ \\                 | | (_)     \n#  | |_| | __ _  ___ _ __ | |_ _  ___ \n#  |  _  |/ _` |/ _ \\ '_ \\| __| |/ __|\n#  | | | | (_| |  __/ | | | |_| | (__ \n#  \\_| |_/\\__, |\\___|_| |_|\\__|_|\\___|\n#          __/ |\n#  _    _ |___/ \n# | |  | |                / _| |\n# | |  | | ___ _ __ _  __| |_| | _____      ____\n# | |/\\| |/ _ \\ '__| |/ /|  _| |/ _ \\ \\ /\\ / / ___|\n# \\  /\\  / (_) | | | | ( | | | | (_) \\ V  V /\\__ \\\n#  \\/  \\/ \\___/|_| |_|\\_\\|_| |_|\\___/ \\_/\\_/ |___/\n#\n# This file was automatically generated by gh-aw (v0.68.3). DO NOT EDIT.\n#\n# To update this file, edit the corresponding .md file and run:\n#   gh aw compile\n# Not all edits will cause changes to this file.\n#\n# For more information: https://github.github.com/gh-aw/introduction/overview/\n#\n# Daily triage of PRs with new-fixture/via-editor labels to validate fixture JSON metadata\n#\n# Secrets used:\n#   - COPILOT_GITHUB_TOKEN\n#   - GH_AW_GITHUB_MCP_SERVER_TOKEN\n#   - GH_AW_GITHUB_TOKEN\n#   - GITHUB_TOKEN\n#\n# Custom actions used:\n#   - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n#   - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1\n#   - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n#   - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n#   - github/gh-aw-actions/setup@07c7335cd76c4d4d9f00dd7874f85ff55ed71f24 # v0.71.3\n#\n# Container images used:\n#   - ghcr.io/github/gh-aw-firewall/agent:0.25.20\n#   - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20\n#   - ghcr.io/github/gh-aw-firewall/squid:0.25.20\n#   - ghcr.io/github/gh-aw-mcpg:v0.2.19\n#   - ghcr.io/github/github-mcp-server:v0.32.0\n#   - node:lts-alpine\n\nname: \"Fixture Metadata Triage\"\n\"on\":\n  workflow_dispatch:\n    inputs:\n      aw_context:\n        default: \"\"\n        description: Agent caller context (used internally by Agentic Workflows).\n        required: false\n        type: string\n      dry-run:\n        default: false\n        description: If true, report what would be done without making changes\n        type: boolean\n\npermissions: {}\n\nconcurrency:\n  group: \"gh-aw-${{ github.workflow }}\"\n\nrun-name: \"Fixture Metadata Triage\"\n\njobs:\n  activation:\n    runs-on: ubuntu-slim\n    permissions:\n      actions: read\n      contents: read\n    outputs:\n      comment_id: \"\"\n      comment_repo: \"\"\n      lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}\n      model: ${{ steps.generate_aw_info.outputs.model }}\n      secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}\n      setup-trace-id: ${{ steps.setup.outputs.trace-id }}\n      stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }}\n    steps:\n      - name: Setup Scripts\n        id: setup\n        uses: github/gh-aw-actions/setup@07c7335cd76c4d4d9f00dd7874f85ff55ed71f24 # v0.71.3\n        with:\n          destination: ${{ runner.temp }}/gh-aw/actions\n          job-name: ${{ github.job }}\n      - name: Generate agentic run info\n        id: generate_aw_info\n        env:\n          GH_AW_INFO_ENGINE_ID: \"copilot\"\n          GH_AW_INFO_ENGINE_NAME: \"GitHub Copilot CLI\"\n          GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }}\n          GH_AW_INFO_VERSION: \"1.0.21\"\n          GH_AW_INFO_AGENT_VERSION: \"1.0.21\"\n          GH_AW_INFO_CLI_VERSION: \"v0.68.3\"\n          GH_AW_INFO_WORKFLOW_NAME: \"Fixture Metadata Triage\"\n          GH_AW_INFO_EXPERIMENTAL: \"false\"\n          GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: \"true\"\n          GH_AW_INFO_STAGED: \"false\"\n          GH_AW_INFO_ALLOWED_DOMAINS: '[\"defaults\"]'\n          GH_AW_INFO_FIREWALL_ENABLED: \"true\"\n          GH_AW_INFO_AWF_VERSION: \"v0.25.20\"\n          GH_AW_INFO_AWMG_VERSION: \"\"\n          GH_AW_INFO_FIREWALL_TYPE: \"squid\"\n          GH_AW_COMPILED_STRICT: \"true\"\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs');\n            await main(core, context);\n      - name: Validate COPILOT_GITHUB_TOKEN secret\n        id: validate-secret\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh\" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n        env:\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n      - name: Checkout .github and .agents folders\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n          sparse-checkout: |\n            .github\n            .agents\n          sparse-checkout-cone-mode: true\n          fetch-depth: 1\n      - name: Check workflow lock file\n        id: check-lock-file\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_WORKFLOW_FILE: \"fixture-metadata-triage.lock.yml\"\n          GH_AW_CONTEXT_WORKFLOW_REF: \"${{ github.workflow_ref }}\"\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs');\n            await main();\n      - name: Check compile-agentic version\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_COMPILED_VERSION: \"v0.68.3\"\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/check_version_updates.cjs');\n            await main();\n      - name: Create prompt with built-in context\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl\n          GH_AW_GITHUB_ACTOR: ${{ github.actor }}\n          GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}\n          GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}\n          GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}\n          GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}\n          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}\n          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}\n          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}\n        # poutine:ignore untrusted_checkout_exec\n        run: |\n          bash \"${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh\"\n          {\n          cat << 'GH_AW_PROMPT_b772d228880039bc_EOF'\n          <system>\n          GH_AW_PROMPT_b772d228880039bc_EOF\n          cat \"${RUNNER_TEMP}/gh-aw/prompts/xpia.md\"\n          cat \"${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md\"\n          cat \"${RUNNER_TEMP}/gh-aw/prompts/markdown.md\"\n          cat \"${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md\"\n          cat << 'GH_AW_PROMPT_b772d228880039bc_EOF'\n          <safe-output-tools>\n          Tools: add_comment, add_labels, missing_tool, missing_data, noop\n          </safe-output-tools>\n          <github-context>\n          The following GitHub context information is available for this workflow:\n          {{#if __GH_AW_GITHUB_ACTOR__ }}\n          - **actor**: __GH_AW_GITHUB_ACTOR__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_REPOSITORY__ }}\n          - **repository**: __GH_AW_GITHUB_REPOSITORY__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_WORKSPACE__ }}\n          - **workspace**: __GH_AW_GITHUB_WORKSPACE__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}\n          - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}\n          - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}\n          - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}\n          - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_RUN_ID__ }}\n          - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__\n          {{/if}}\n          </github-context>\n          \n          GH_AW_PROMPT_b772d228880039bc_EOF\n          cat \"${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md\"\n          cat << 'GH_AW_PROMPT_b772d228880039bc_EOF'\n          </system>\n          {{#runtime-import .github/workflows/fixture-metadata-triage.md}}\n          GH_AW_PROMPT_b772d228880039bc_EOF\n          } > \"$GH_AW_PROMPT\"\n      - name: Interpolate variables and render templates\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs');\n            await main();\n      - name: Substitute placeholders\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_GITHUB_ACTOR: ${{ github.actor }}\n          GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}\n          GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}\n          GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}\n          GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}\n          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}\n          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}\n          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            \n            const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs');\n            \n            // Call the substitution function\n            return await substitutePlaceholders({\n              file: process.env.GH_AW_PROMPT,\n              substitutions: {\n                GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,\n                GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,\n                GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,\n                GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,\n                GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,\n                GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,\n                GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,\n                GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE\n              }\n            });\n      - name: Validate prompt placeholders\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n        # poutine:ignore untrusted_checkout_exec\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh\"\n      - name: Print prompt\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n        # poutine:ignore untrusted_checkout_exec\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh\"\n      - name: Upload activation artifact\n        if: success()\n        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n        with:\n          name: activation\n          path: |\n            /tmp/gh-aw/aw_info.json\n            /tmp/gh-aw/aw-prompts/prompt.txt\n            /tmp/gh-aw/github_rate_limits.jsonl\n          if-no-files-found: ignore\n          retention-days: 1\n\n  agent:\n    needs: activation\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      pull-requests: read\n    env:\n      DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}\n      GH_AW_ASSETS_ALLOWED_EXTS: \"\"\n      GH_AW_ASSETS_BRANCH: \"\"\n      GH_AW_ASSETS_MAX_SIZE_KB: 0\n      GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs\n      GH_AW_WORKFLOW_ID_SANITIZED: fixturemetadatatriage\n    outputs:\n      agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}\n      checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}\n      effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}\n      has_patch: ${{ steps.collect_output.outputs.has_patch }}\n      inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}\n      mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}\n      model: ${{ needs.activation.outputs.model }}\n      model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}\n      output: ${{ steps.collect_output.outputs.output }}\n      output_types: ${{ steps.collect_output.outputs.output_types }}\n      setup-trace-id: ${{ steps.setup.outputs.trace-id }}\n    steps:\n      - name: Setup Scripts\n        id: setup\n        uses: github/gh-aw-actions/setup@07c7335cd76c4d4d9f00dd7874f85ff55ed71f24 # v0.71.3\n        with:\n          destination: ${{ runner.temp }}/gh-aw/actions\n          job-name: ${{ github.job }}\n          trace-id: ${{ needs.activation.outputs.setup-trace-id }}\n      - name: Set runtime paths\n        id: set-runtime-paths\n        run: |\n          {\n            echo \"GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl\"\n            echo \"GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json\"\n            echo \"GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json\"\n          } >> \"$GITHUB_OUTPUT\"\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Create gh-aw temp directory\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh\"\n      - name: Configure gh CLI for GitHub Enterprise\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh\"\n        env:\n          GH_TOKEN: ${{ github.token }}\n      - name: Configure Git credentials\n        env:\n          REPO_NAME: ${{ github.repository }}\n          SERVER_URL: ${{ github.server_url }}\n          GITHUB_TOKEN: ${{ github.token }}\n        run: |\n          git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n          git config --global user.name \"github-actions[bot]\"\n          git config --global am.keepcr true\n          # Re-authenticate git with GitHub token\n          SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n          git remote set-url origin \"https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n          echo \"Git configured with standard GitHub Actions identity\"\n      - name: Checkout PR branch\n        id: checkout-pr\n        if: |\n          github.event.pull_request || github.event.issue.pull_request\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');\n            await main();\n      - name: Install GitHub Copilot CLI\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh\" 1.0.21\n        env:\n          GH_HOST: github.com\n      - name: Install AWF binary\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh\" v0.25.20\n      - name: Parse integrity filter lists\n        id: parse-guard-vars\n        env:\n          GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }}\n          GH_AW_TRUSTED_USERS_VAR: ${{ vars.GH_AW_GITHUB_TRUSTED_USERS || '' }}\n          GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }}\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh\"\n      - name: Download container images\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh\" ghcr.io/github/gh-aw-firewall/agent:0.25.20 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20 ghcr.io/github/gh-aw-firewall/squid:0.25.20 ghcr.io/github/gh-aw-mcpg:v0.2.19 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine\n      - name: Write Safe Outputs Config\n        run: |\n          mkdir -p \"${RUNNER_TEMP}/gh-aw/safeoutputs\"\n          mkdir -p /tmp/gh-aw/safeoutputs\n          mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs\n          cat > \"${RUNNER_TEMP}/gh-aw/safeoutputs/config.json\" << 'GH_AW_SAFE_OUTPUTS_CONFIG_0d0dfcc4303f7582_EOF'\n          {\"add_comment\":{\"max\":1},\"add_labels\":{\"allowed\":[\"incomplete\"]},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}\n          GH_AW_SAFE_OUTPUTS_CONFIG_0d0dfcc4303f7582_EOF\n      - name: Write Safe Outputs Tools\n        env:\n          GH_AW_TOOLS_META_JSON: |\n            {\n              \"description_suffixes\": {\n                \"add_comment\": \" CONSTRAINTS: Maximum 1 comment(s) can be added. Supports reply_to_id for discussion threading.\",\n                \"add_labels\": \" CONSTRAINTS: Only these labels are allowed: [\\\"incomplete\\\"].\"\n              },\n              \"repo_params\": {},\n              \"dynamic_tools\": []\n            }\n          GH_AW_VALIDATION_JSON: |\n            {\n              \"add_comment\": {\n                \"defaultMax\": 1,\n                \"fields\": {\n                  \"body\": {\n                    \"required\": true,\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 65000\n                  },\n                  \"item_number\": {\n                    \"issueOrPRNumber\": true\n                  },\n                  \"reply_to_id\": {\n                    \"type\": \"string\",\n                    \"maxLength\": 256\n                  },\n                  \"repo\": {\n                    \"type\": \"string\",\n                    \"maxLength\": 256\n                  }\n                }\n              },\n              \"add_labels\": {\n                \"defaultMax\": 5,\n                \"fields\": {\n                  \"item_number\": {\n                    \"issueNumberOrTemporaryId\": true\n                  },\n                  \"labels\": {\n                    \"required\": true,\n                    \"type\": \"array\",\n                    \"itemType\": \"string\",\n                    \"itemSanitize\": true,\n                    \"itemMaxLength\": 128\n                  },\n                  \"repo\": {\n                    \"type\": \"string\",\n                    \"maxLength\": 256\n                  }\n                }\n              },\n              \"missing_data\": {\n                \"defaultMax\": 20,\n                \"fields\": {\n                  \"alternatives\": {\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 256\n                  },\n                  \"context\": {\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 256\n                  },\n                  \"data_type\": {\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 128\n                  },\n                  \"reason\": {\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 256\n                  }\n                }\n              },\n              \"missing_tool\": {\n                \"defaultMax\": 20,\n                \"fields\": {\n                  \"alternatives\": {\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 512\n                  },\n                  \"reason\": {\n                    \"required\": true,\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 256\n                  },\n                  \"tool\": {\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 128\n                  }\n                }\n              },\n              \"noop\": {\n                \"defaultMax\": 1,\n                \"fields\": {\n                  \"message\": {\n                    \"required\": true,\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 65000\n                  }\n                }\n              },\n              \"report_incomplete\": {\n                \"defaultMax\": 5,\n                \"fields\": {\n                  \"details\": {\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 65000\n                  },\n                  \"reason\": {\n                    \"required\": true,\n                    \"type\": \"string\",\n                    \"sanitize\": true,\n                    \"maxLength\": 1024\n                  }\n                }\n              }\n            }\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs');\n            await main();\n      - name: Generate Safe Outputs MCP Server Config\n        id: safe-outputs-config\n        run: |\n          # Generate a secure random API key (360 bits of entropy, 40+ chars)\n          # Mask immediately to prevent timing vulnerabilities\n          API_KEY=$(openssl rand -base64 45 | tr -d '/+=')\n          echo \"::add-mask::${API_KEY}\"\n          \n          PORT=3001\n          \n          # Set outputs for next steps\n          {\n            echo \"safe_outputs_api_key=${API_KEY}\"\n            echo \"safe_outputs_port=${PORT}\"\n          } >> \"$GITHUB_OUTPUT\"\n          \n          echo \"Safe Outputs MCP server will run on port ${PORT}\"\n          \n      - name: Start Safe Outputs MCP HTTP Server\n        id: safe-outputs-start\n        env:\n          DEBUG: '*'\n          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}\n          GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}\n          GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json\n          GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json\n          GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs\n        run: |\n          # Environment variables are set above to prevent template injection\n          export DEBUG\n          export GH_AW_SAFE_OUTPUTS\n          export GH_AW_SAFE_OUTPUTS_PORT\n          export GH_AW_SAFE_OUTPUTS_API_KEY\n          export GH_AW_SAFE_OUTPUTS_TOOLS_PATH\n          export GH_AW_SAFE_OUTPUTS_CONFIG_PATH\n          export GH_AW_MCP_LOG_DIR\n          \n          bash \"${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh\"\n          \n      - name: Start MCP Gateway\n        id: start-mcp-gateway\n        env:\n          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}\n          GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}\n          GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n        run: |\n          set -eo pipefail\n          mkdir -p /tmp/gh-aw/mcp-config\n          \n          # Export gateway environment variables for MCP config and gateway script\n          export MCP_GATEWAY_PORT=\"80\"\n          export MCP_GATEWAY_DOMAIN=\"host.docker.internal\"\n          MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')\n          echo \"::add-mask::${MCP_GATEWAY_API_KEY}\"\n          export MCP_GATEWAY_API_KEY\n          export MCP_GATEWAY_PAYLOAD_DIR=\"/tmp/gh-aw/mcp-payloads\"\n          mkdir -p \"${MCP_GATEWAY_PAYLOAD_DIR}\"\n          export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD=\"524288\"\n          export DEBUG=\"*\"\n          \n          export GH_AW_ENGINE=\"copilot\"\n          export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '\"${GITHUB_WORKSPACE}\"':'\"${GITHUB_WORKSPACE}\"':rw ghcr.io/github/gh-aw-mcpg:v0.2.19'\n          \n          mkdir -p /home/runner/.copilot\n          cat << GH_AW_MCP_CONFIG_08bc358d5f12b180_EOF | bash \"${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh\"\n          {\n            \"mcpServers\": {\n              \"github\": {\n                \"type\": \"stdio\",\n                \"container\": \"ghcr.io/github/github-mcp-server:v0.32.0\",\n                \"env\": {\n                  \"GITHUB_HOST\": \"\\${GITHUB_SERVER_URL}\",\n                  \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"\\${GITHUB_MCP_SERVER_TOKEN}\",\n                  \"GITHUB_READ_ONLY\": \"1\",\n                  \"GITHUB_TOOLSETS\": \"pull_requests,repos\"\n                },\n                \"guard-policies\": {\n                  \"allow-only\": {\n                    \"approval-labels\": ${{ steps.parse-guard-vars.outputs.approval_labels }},\n                    \"blocked-users\": ${{ steps.parse-guard-vars.outputs.blocked_users }},\n                    \"min-integrity\": \"approved\",\n                    \"repos\": \"all\",\n                    \"trusted-users\": ${{ steps.parse-guard-vars.outputs.trusted_users }}\n                  }\n                }\n              },\n              \"safeoutputs\": {\n                \"type\": \"http\",\n                \"url\": \"http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT\",\n                \"headers\": {\n                  \"Authorization\": \"\\${GH_AW_SAFE_OUTPUTS_API_KEY}\"\n                },\n                \"guard-policies\": {\n                  \"write-sink\": {\n                    \"accept\": [\n                      \"*\"\n                    ]\n                  }\n                }\n              }\n            },\n            \"gateway\": {\n              \"port\": $MCP_GATEWAY_PORT,\n              \"domain\": \"${MCP_GATEWAY_DOMAIN}\",\n              \"apiKey\": \"${MCP_GATEWAY_API_KEY}\",\n              \"payloadDir\": \"${MCP_GATEWAY_PAYLOAD_DIR}\"\n            }\n          }\n          GH_AW_MCP_CONFIG_08bc358d5f12b180_EOF\n      - name: Download activation artifact\n        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1\n        with:\n          name: activation\n          path: /tmp/gh-aw\n      - name: Clean git credentials\n        continue-on-error: true\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh\"\n      - name: Execute GitHub Copilot CLI\n        id: agentic_execution\n        # Copilot CLI tool arguments (sorted):\n        timeout-minutes: 20\n        run: |\n          set -o pipefail\n          touch /tmp/gh-aw/agent-step-summary.md\n          (umask 177 && touch /tmp/gh-aw/agent-stdio.log)\n          # shellcheck disable=SC1003\n          sudo -E awf --container-workdir \"${GITHUB_WORKSPACE}\" --mount \"${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro\" --mount \"${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro\" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.20 --skip-pull --enable-api-proxy \\\n            -- /bin/bash -c 'node ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir \"${GITHUB_WORKSPACE}\" --prompt \"$(cat /tmp/gh-aw/aw-prompts/prompt.txt)\"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log\n        env:\n          COPILOT_AGENT_RUNNER_TYPE: STANDALONE\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}\n          GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json\n          GH_AW_PHASE: agent\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_VERSION: v0.68.3\n          GITHUB_API_URL: ${{ github.api_url }}\n          GITHUB_AW: true\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n          GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          GITHUB_REF_NAME: ${{ github.ref_name }}\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md\n          GITHUB_WORKSPACE: ${{ github.workspace }}\n          GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com\n          GIT_AUTHOR_NAME: github-actions[bot]\n          GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com\n          GIT_COMMITTER_NAME: github-actions[bot]\n          XDG_CONFIG_HOME: /home/runner\n      - name: Detect Copilot errors\n        id: detect-copilot-errors\n        if: always()\n        continue-on-error: true\n        run: node \"${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs\"\n      - name: Configure Git credentials\n        env:\n          REPO_NAME: ${{ github.repository }}\n          SERVER_URL: ${{ github.server_url }}\n          GITHUB_TOKEN: ${{ github.token }}\n        run: |\n          git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n          git config --global user.name \"github-actions[bot]\"\n          git config --global am.keepcr true\n          # Re-authenticate git with GitHub token\n          SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n          git remote set-url origin \"https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n          echo \"Git configured with standard GitHub Actions identity\"\n      - name: Copy Copilot session state files to logs\n        if: always()\n        continue-on-error: true\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh\"\n      - name: Stop MCP Gateway\n        if: always()\n        continue-on-error: true\n        env:\n          MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}\n          MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}\n          GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}\n        run: |\n          bash \"${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh\" \"$GATEWAY_PID\"\n      - name: Redact secrets in logs\n        if: always()\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs');\n            await main();\n        env:\n          GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'\n          SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}\n          SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}\n          SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - name: Append agent step summary\n        if: always()\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh\"\n      - name: Copy Safe Outputs\n        if: always()\n        env:\n          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}\n        run: |\n          mkdir -p /tmp/gh-aw\n          cp \"$GH_AW_SAFE_OUTPUTS\" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true\n      - name: Ingest agent output\n        id: collect_output\n        if: always()\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_ALLOWED_DOMAINS: \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com\"\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_API_URL: ${{ github.api_url }}\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs');\n            await main();\n      - name: Parse agent logs for step summary\n        if: always()\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs');\n            await main();\n      - name: Parse MCP Gateway logs for step summary\n        if: always()\n        id: parse-mcp-gateway\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs');\n            await main();\n      - name: Print firewall logs\n        if: always()\n        continue-on-error: true\n        env:\n          AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs\n        run: |\n          # Fix permissions on firewall logs so they can be uploaded as artifacts\n          # AWF runs with sudo, creating files owned by root\n          sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true\n          # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)\n          if command -v awf &> /dev/null; then\n            awf logs summary | tee -a \"$GITHUB_STEP_SUMMARY\"\n          else\n            echo 'AWF binary not installed, skipping firewall log summary'\n          fi\n      - name: Parse token usage for step summary\n        if: always()\n        continue-on-error: true\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs');\n            await main();\n      - name: Write agent output placeholder if missing\n        if: always()\n        run: |\n          if [ ! -f /tmp/gh-aw/agent_output.json ]; then\n            echo '{\"items\":[]}' > /tmp/gh-aw/agent_output.json\n          fi\n      - name: Upload agent artifacts\n        if: always()\n        continue-on-error: true\n        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n        with:\n          name: agent\n          path: |\n            /tmp/gh-aw/aw-prompts/prompt.txt\n            /tmp/gh-aw/sandbox/agent/logs/\n            /tmp/gh-aw/redacted-urls.log\n            /tmp/gh-aw/mcp-logs/\n            /tmp/gh-aw/proxy-logs/\n            !/tmp/gh-aw/proxy-logs/proxy-tls/\n            /tmp/gh-aw/agent_usage.json\n            /tmp/gh-aw/agent-stdio.log\n            /tmp/gh-aw/agent/\n            /tmp/gh-aw/github_rate_limits.jsonl\n            /tmp/gh-aw/safeoutputs.jsonl\n            /tmp/gh-aw/agent_output.json\n            /tmp/gh-aw/aw-*.patch\n            /tmp/gh-aw/aw-*.bundle\n            /tmp/gh-aw/sandbox/firewall/logs/\n            /tmp/gh-aw/sandbox/firewall/audit/\n          if-no-files-found: ignore\n\n  conclusion:\n    needs:\n      - activation\n      - agent\n      - detection\n      - safe_outputs\n    if: >\n      always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||\n      needs.activation.outputs.stale_lock_file_failed == 'true')\n    runs-on: ubuntu-slim\n    permissions:\n      contents: read\n      discussions: write\n      issues: write\n      pull-requests: write\n    concurrency:\n      group: \"gh-aw-conclusion-fixture-metadata-triage\"\n      cancel-in-progress: false\n    outputs:\n      incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }}\n      noop_message: ${{ steps.noop.outputs.noop_message }}\n      tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}\n      total_count: ${{ steps.missing_tool.outputs.total_count }}\n    steps:\n      - name: Setup Scripts\n        id: setup\n        uses: github/gh-aw-actions/setup@07c7335cd76c4d4d9f00dd7874f85ff55ed71f24 # v0.71.3\n        with:\n          destination: ${{ runner.temp }}/gh-aw/actions\n          job-name: ${{ github.job }}\n          trace-id: ${{ needs.activation.outputs.setup-trace-id }}\n      - name: Download agent output artifact\n        id: download-agent-output\n        continue-on-error: true\n        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1\n        with:\n          name: agent\n          path: /tmp/gh-aw/\n      - name: Setup agent output environment variable\n        id: setup-agent-output-env\n        if: steps.download-agent-output.outcome == 'success'\n        run: |\n          mkdir -p /tmp/gh-aw/\n          find \"/tmp/gh-aw/\" -type f -print\n          echo \"GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json\" >> \"$GITHUB_OUTPUT\"\n      - name: Process no-op messages\n        id: noop\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}\n          GH_AW_NOOP_MAX: \"1\"\n          GH_AW_WORKFLOW_NAME: \"Fixture Metadata Triage\"\n          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n          GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}\n          GH_AW_NOOP_REPORT_AS_ISSUE: \"true\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs');\n            await main();\n      - name: Log detection run\n        id: detection_runs\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Fixture Metadata Triage\"\n          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n          GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}\n          GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_detection_runs.cjs');\n            await main();\n      - name: Record missing tool\n        id: missing_tool\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}\n          GH_AW_MISSING_TOOL_CREATE_ISSUE: \"true\"\n          GH_AW_WORKFLOW_NAME: \"Fixture Metadata Triage\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs');\n            await main();\n      - name: Record incomplete\n        id: report_incomplete\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}\n          GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: \"true\"\n          GH_AW_WORKFLOW_NAME: \"Fixture Metadata Triage\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/report_incomplete_handler.cjs');\n            await main();\n      - name: Handle agent failure\n        id: handle_agent_failure\n        if: always()\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Fixture Metadata Triage\"\n          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n          GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}\n          GH_AW_WORKFLOW_ID: \"fixture-metadata-triage\"\n          GH_AW_ENGINE_ID: \"copilot\"\n          GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}\n          GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}\n          GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}\n          GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }}\n          GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }}\n          GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }}\n          GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}\n          GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }}\n          GH_AW_GROUP_REPORTS: \"false\"\n          GH_AW_FAILURE_REPORT_AS_ISSUE: \"true\"\n          GH_AW_TIMEOUT_MINUTES: \"20\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');\n            await main();\n\n  detection:\n    needs:\n      - activation\n      - agent\n    if: >\n      always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true')\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    outputs:\n      detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}\n      detection_reason: ${{ steps.detection_conclusion.outputs.reason }}\n      detection_success: ${{ steps.detection_conclusion.outputs.success }}\n    steps:\n      - name: Setup Scripts\n        id: setup\n        uses: github/gh-aw-actions/setup@07c7335cd76c4d4d9f00dd7874f85ff55ed71f24 # v0.71.3\n        with:\n          destination: ${{ runner.temp }}/gh-aw/actions\n          job-name: ${{ github.job }}\n          trace-id: ${{ needs.activation.outputs.setup-trace-id }}\n      - name: Download agent output artifact\n        id: download-agent-output\n        continue-on-error: true\n        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1\n        with:\n          name: agent\n          path: /tmp/gh-aw/\n      - name: Setup agent output environment variable\n        id: setup-agent-output-env\n        if: steps.download-agent-output.outcome == 'success'\n        run: |\n          mkdir -p /tmp/gh-aw/\n          find \"/tmp/gh-aw/\" -type f -print\n          echo \"GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json\" >> \"$GITHUB_OUTPUT\"\n      - name: Checkout repository for patch context\n        if: needs.agent.outputs.has_patch == 'true'\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      # --- Threat Detection ---\n      - name: Clean stale firewall files from agent artifact\n        run: |\n          rm -rf /tmp/gh-aw/sandbox/firewall/logs\n          rm -rf /tmp/gh-aw/sandbox/firewall/audit\n      - name: Download container images\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh\" ghcr.io/github/gh-aw-firewall/agent:0.25.20 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20 ghcr.io/github/gh-aw-firewall/squid:0.25.20\n      - name: Check if detection needed\n        id: detection_guard\n        if: always()\n        env:\n          OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }}\n          HAS_PATCH: ${{ needs.agent.outputs.has_patch }}\n        run: |\n          if [[ -n \"$OUTPUT_TYPES\" || \"$HAS_PATCH\" == \"true\" ]]; then\n            echo \"run_detection=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH\"\n          else\n            echo \"run_detection=false\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection skipped: no agent outputs or patches to analyze\"\n          fi\n      - name: Clear MCP configuration for detection\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          rm -f /tmp/gh-aw/mcp-config/mcp-servers.json\n          rm -f /home/runner/.copilot/mcp-config.json\n          rm -f \"$GITHUB_WORKSPACE/.gemini/settings.json\"\n      - name: Prepare threat detection files\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          mkdir -p /tmp/gh-aw/threat-detection/aw-prompts\n          cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true\n          cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true\n          for f in /tmp/gh-aw/aw-*.patch; do\n            [ -f \"$f\" ] && cp \"$f\" /tmp/gh-aw/threat-detection/ 2>/dev/null || true\n          done\n          for f in /tmp/gh-aw/aw-*.bundle; do\n            [ -f \"$f\" ] && cp \"$f\" /tmp/gh-aw/threat-detection/ 2>/dev/null || true\n          done\n          echo \"Prepared threat detection files:\"\n          ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true\n      - name: Setup threat detection\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          WORKFLOW_NAME: \"Fixture Metadata Triage\"\n          WORKFLOW_DESCRIPTION: \"Daily triage of PRs with new-fixture/via-editor labels to validate fixture JSON metadata\"\n          HAS_PATCH: ${{ needs.agent.outputs.has_patch }}\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs');\n            await main();\n      - name: Ensure threat-detection directory and log\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          mkdir -p /tmp/gh-aw/threat-detection\n          touch /tmp/gh-aw/threat-detection/detection.log\n      - name: Install GitHub Copilot CLI\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh\" 1.0.21\n        env:\n          GH_HOST: github.com\n      - name: Install AWF binary\n        run: bash \"${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh\" v0.25.20\n      - name: Execute GitHub Copilot CLI\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        id: detection_agentic_execution\n        # Copilot CLI tool arguments (sorted):\n        timeout-minutes: 20\n        run: |\n          set -o pipefail\n          touch /tmp/gh-aw/agent-step-summary.md\n          (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)\n          # shellcheck disable=SC1003\n          sudo -E awf --container-workdir \"${GITHUB_WORKSPACE}\" --mount \"${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro\" --mount \"${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro\" --env-all --exclude-env COPILOT_GITHUB_TOKEN --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.20 --skip-pull --enable-api-proxy \\\n            -- /bin/bash -c 'node ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir \"${GITHUB_WORKSPACE}\" --prompt \"$(cat /tmp/gh-aw/aw-prompts/prompt.txt)\"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log\n        env:\n          COPILOT_AGENT_RUNNER_TYPE: STANDALONE\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }}\n          GH_AW_PHASE: detection\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_VERSION: v0.68.3\n          GITHUB_API_URL: ${{ github.api_url }}\n          GITHUB_AW: true\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n          GITHUB_REF_NAME: ${{ github.ref_name }}\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md\n          GITHUB_WORKSPACE: ${{ github.workspace }}\n          GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com\n          GIT_AUTHOR_NAME: github-actions[bot]\n          GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com\n          GIT_COMMITTER_NAME: github-actions[bot]\n          XDG_CONFIG_HOME: /home/runner\n      - name: Upload threat detection log\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n        with:\n          name: detection\n          path: /tmp/gh-aw/threat-detection/detection.log\n          if-no-files-found: ignore\n      - name: Parse and conclude threat detection\n        id: detection_conclusion\n        if: always()\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}\n          GH_AW_DETECTION_CONTINUE_ON_ERROR: \"true\"\n        with:\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs');\n            await main();\n\n  safe_outputs:\n    needs:\n      - activation\n      - agent\n      - detection\n    if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success'\n    runs-on: ubuntu-slim\n    permissions:\n      contents: read\n      discussions: write\n      issues: write\n      pull-requests: write\n    timeout-minutes: 15\n    env:\n      GH_AW_CALLER_WORKFLOW_ID: \"${{ github.repository }}/fixture-metadata-triage\"\n      GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}\n      GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}\n      GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}\n      GH_AW_ENGINE_ID: \"copilot\"\n      GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}\n      GH_AW_WORKFLOW_ID: \"fixture-metadata-triage\"\n      GH_AW_WORKFLOW_NAME: \"Fixture Metadata Triage\"\n    outputs:\n      code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}\n      code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}\n      comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }}\n      comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }}\n      create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}\n      create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}\n      process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}\n      process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}\n    steps:\n      - name: Setup Scripts\n        id: setup\n        uses: github/gh-aw-actions/setup@07c7335cd76c4d4d9f00dd7874f85ff55ed71f24 # v0.71.3\n        with:\n          destination: ${{ runner.temp }}/gh-aw/actions\n          job-name: ${{ github.job }}\n          trace-id: ${{ needs.activation.outputs.setup-trace-id }}\n      - name: Download agent output artifact\n        id: download-agent-output\n        continue-on-error: true\n        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1\n        with:\n          name: agent\n          path: /tmp/gh-aw/\n      - name: Setup agent output environment variable\n        id: setup-agent-output-env\n        if: steps.download-agent-output.outcome == 'success'\n        run: |\n          mkdir -p /tmp/gh-aw/\n          find \"/tmp/gh-aw/\" -type f -print\n          echo \"GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json\" >> \"$GITHUB_OUTPUT\"\n      - name: Configure GH_HOST for enterprise compatibility\n        id: ghes-host-config\n        shell: bash\n        run: |\n          # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct\n          # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.\n          GH_HOST=\"${GITHUB_SERVER_URL#https://}\"\n          GH_HOST=\"${GH_HOST#http://}\"\n          echo \"GH_HOST=${GH_HOST}\" >> \"$GITHUB_ENV\"\n      - name: Process Safe Outputs\n        id: process_safe_outputs\n        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}\n          GH_AW_ALLOWED_DOMAINS: \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com\"\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_API_URL: ${{ github.api_url }}\n          GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: \"{\\\"add_comment\\\":{\\\"max\\\":1},\\\"add_labels\\\":{\\\"allowed\\\":[\\\"incomplete\\\"]},\\\"create_report_incomplete_issue\\\":{},\\\"missing_data\\\":{},\\\"missing_tool\\\":{},\\\"noop\\\":{\\\"max\\\":1,\\\"report-as-issue\\\":\\\"true\\\"},\\\"report_incomplete\\\":{}}\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io, getOctokit);\n            const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs');\n            await main();\n      - name: Upload Safe Outputs Items\n        if: always()\n        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n        with:\n          name: safe-outputs-items\n          path: |\n            /tmp/gh-aw/safe-output-items.jsonl\n            /tmp/gh-aw/temporary-id-map.json\n          if-no-files-found: ignore\n\n"
  },
  {
    "path": ".github/workflows/fixture-metadata-triage.md",
    "content": "---\nname: Fixture Metadata Triage\ndescription: Daily triage of PRs with new-fixture/via-editor labels to validate fixture JSON metadata\n\non:\n  workflow_dispatch:\n    inputs:\n      dry-run:\n        type: boolean\n        description: If true, report what would be done without making changes\n        default: false\n\npermissions:\n  contents: read\n  pull-requests: read\n\nsafe-outputs:\n  add-comment:\n    pull-requests: true\n  add-labels:\n    allowed: [incomplete]\n\ntools:\n  github:\n    min-integrity: approved\n    toolsets: [pull_requests, repos]\n---\n\n# Fixture Metadata Triage Agent\n\nYou are an automated triage system for PRs adding new fixtures to the Open Fixture Library. Your task is to identify PRs that have changed fixture JSON files but are missing required metadata.\n\n## Your Mission\n\n1. Find all open PRs with BOTH labels: `new-fixture` AND `via-editor`\n2. Exclude any PRs that have already been reviewed manually (by a human)\n3. Exclude any PRs that already have the `incomplete` label (already processed)\n4. For each PR, get the list of changed files\n5. Identify JSON files that follow the fixture schema\n6. Check for required metadata (links.manual OR links.productPage)\n7. Flag incomplete PRs by adding the `incomplete` label and commenting\n\n## Triage Rules\n\n- **Skip** a PR if:\n\n  - Already has the `incomplete` label\n  - Has any existing reviews\n  - No files match the fixture schema (\"$schema\": \".../schemas/fixture.json\")\n\n- **Flag** a PR if:\n  - Modified at least one file with the fixture schema\n  - AND that file has empty/missing `links` object\n  - OR both `links.manual` AND `links.productPage` are missing or empty\n\n## Validation Logic\n\nFor each fixture JSON file in the PR:\n\n1. Check if file contains `\"$schema\": \".../schemas/fixture.json\"`\n2. Parse the `links` object\n3. If `links.manual` EXISTS and is not empty → valid\n4. If `links.productPage` EXISTS and is not empty → valid\n5. If NEITHER exists OR both are empty → flag the PR\n\n## Actions on Flagged PR\n\nOnly if `dry-run` input is NOT true:\n\n1. Add label: `incomplete`\n2. Add comment: \"Missing required metadata: Manual and Product Page\"\n\nIf `dry-run` IS true, only report what would be done - do NOT add labels or comments.\n\n## Output\n\nGenerate a report:\n\n- Total PRs checked this run\n- PRs skipped (no fixture files or already labelled)\n- PRs flagged (incomplete metadata)\n- PRs valid (have metadata)\n"
  },
  {
    "path": ".github/workflows/lighthouse-production.yaml",
    "content": "name: Lighthouse\non:\n  schedule:\n    - cron: '30 18 * * *' # everyday 18:30 UTC\n  workflow_dispatch:\njobs:\n  production:\n    name: Production\n    runs-on: ubuntu-latest\n    if: github.repository == 'OpenLightingProject/open-fixture-library'\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6.0.2\n      - name: Run the Lighthouse CI\n        uses: treosh/lighthouse-ci-action@12.6.2\n        with:\n          urls: |\n            https://open-fixture-library.org/\n            https://open-fixture-library.org/chroma-q/color-force-ii-72\n            https://open-fixture-library.org/categories/Color%20Changer\n          runs: 3\n          uploadArtifacts: true\n          temporaryPublicStorage: true\n"
  },
  {
    "path": ".github/workflows/lighthouse-review.yaml",
    "content": "name: Lighthouse\non:\n  pull_request:\n    types: [opened, synchronize, reopened, labeled]\nconcurrency:\n  group: lighthouse-review-${{ github.ref }}\n  cancel-in-progress: true\njobs:\n  review:\n    name: Review\n    runs-on: ubuntu-latest\n    if: contains(github.event.pull_request.labels.*.name, 'component-ui')\n    env:\n      NODE_ENV: production\n      ALLOW_SEARCH_INDEXING: allowed\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6.0.2\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}\n      - name: Setup Node.js v24\n        uses: actions/setup-node@v6.4.0\n        with:\n          node-version: 24\n          cache: 'npm'\n      - name: Install dependencies\n        run: npm ci --include=dev\n      - name: Build\n        run: npm run build\n      - name: Run the Lighthouse CI\n        uses: treosh/lighthouse-ci-action@12.6.2\n        with:\n          urls: |\n            http://localhost:3000/\n            http://localhost:3000/chroma-q/color-force-ii-72\n            http://localhost:3000/categories/Color%20Changer\n          runs: 1\n          configPath: '.github/lighthouserc.json'\n          uploadArtifacts: true\n          temporaryPublicStorage: true\n        env:\n          LHCI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          GITHUB_PR_NUMBER: ${{ github.event.number }}\n"
  },
  {
    "path": ".github/workflows/test.yaml",
    "content": "name: Test\non: pull_request\nconcurrency:\n  group: test-${{ github.ref }}\n  cancel-in-progress: true\njobs:\n  required:\n    name: Required\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6.0.2\n      - name: Setup Node.js v24\n        uses: actions/setup-node@v6.4.0\n        with:\n          node-version: 24\n          cache: 'npm'\n      - name: Install dependencies\n        run: npm ci\n      - name: Build\n        run: npm run build\n      - name: Run ESLint\n        run: npm run lint:eslint\n      - name: Run Stylelint\n        run: npm run lint:stylelint -- --formatter compact\n      - name: Run dmx-value-scaling test\n        run: npm run test:dmx-value-scaling\n      - name: Run fixtures-valid test\n        run: npm run test:fixtures-valid\n      - name: Run http-status test\n        run: npm run test:http-status\n      - name: Run built-files-committed test\n        run: npm run test:built-files-committed\n  status:\n    name: Status\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    env:\n      GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}\n      GITHUB_PR_HEAD_REF: origin/${{ github.head_ref }}\n      GITHUB_PR_BASE_REF: origin/${{ github.base_ref }}\n      GITHUB_USER_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6.0.2\n        with:\n          fetch-depth: 0 # complete history for all branches and tags\n      - name: Setup Node.js v24\n        uses: actions/setup-node@v6.4.0\n        with:\n          node-version: 24\n          cache: 'npm'\n      - name: Install dependencies\n        run: |\n          sudo pip install lxml # for QLC+ fixture-tool-validation export test\n          npm ci\n      - name: Build\n        run: npm run build\n      - name: Run export-diff test\n        run: node tests/github/export-diff.js\n      - name: Run exports-valid test\n        run: node tests/github/exports-valid.js\n      - name: Run schema-version-reminder\n        run: node tests/github/schema-version-reminder.js\n  markdown-link-check:\n    name: Markdown Links\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6.0.2\n      - name: Check Markdown Links in modified files\n        uses: gaurav-nelson/github-action-markdown-link-check@v1\n        with:\n          use-verbose-mode: 'yes'\n          check-modified-files-only: 'yes'\n          base-branch: 'master'\n"
  },
  {
    "path": ".gitignore",
    "content": "# Node build artifacts\nnode_modules/\nnpm-debug.log\n\n# Local development\n*.env\n*.dev.*\n.DS_Store\n*.sublime-*\n.vscode/\n.idea/\n\n# Docker\nDockerfile\ndocker-compose.yml\n\n# Generated files\n.nuxt/\nfixtures/register.json\n\n# Temporary files\ntmp/\n.eslintcache\n\n# secret files\nserver/ofl-secrets.json\nserver/*.log\n"
  },
  {
    "path": ".stylelintrc.yaml",
    "content": "reportNeedlessDisables: true\nreportInvalidScopeDisables: true\nreportDescriptionlessDisables: true\nextends:\n  - '@stylistic/stylelint-config'\n  - stylelint-config-standard-scss\n  - stylelint-config-html/vue\n  - stylelint-config-recess-order\nrules:\n  # `without-alpha` not supported by Sass\n  color-function-alias-notation: with-alpha\n\n  # `modern` not supported by Sass\n  color-function-notation: legacy\n\n  # always long to be consistent\n  color-hex-length: long\n\n  # always numeric to be consistent\n  font-weight-notation: numeric\n\n  # avoid using non-global functions\n  function-no-unknown:\n    - true\n    - ignoreFunctions:\n      - theme-color\n      - color-to-rgb-string\n      - /^[a-z]+\\.[a-z\\-]+$/ # all `@use`d Sass functions\n\n  # causes false positives with Sass\n  nesting-selector-no-missing-scoping-root: null\n\n  # decrease severity for this rule only\n  no-descending-specificity:\n    - true\n    - severity: warning\n\n  # allow Vue pseudo elements\n  selector-pseudo-element-no-unknown:\n    - true\n    - ignorePseudoElements: [\"v-deep\"]\n\n  # simplify rules\n  scss/block-no-redundant-nesting: true\n\n  # prevent comments in generated CSS\n  scss/comment-no-loud: true\n\n  # prevent deprecated color functions\n  scss/function-color-channel: true\n\n  # make imported files more explicit\n  scss/load-partial-extension: always\n\n  # special `@if`/`@else` formatting\n  '@stylistic/block-closing-brace-newline-after':\n    - always\n    - ignoreAtRules:\n      - if\n      - else\n\n  # allow grouping in Sass lists\n  '@stylistic/value-list-max-empty-lines': 1\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Florian & Felix Edelmann\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": "README.md",
    "content": "# Open Fixture Library<br><a href=\"https://open-fixture-library.org/\">open-fixture-library.org</a>\n\n[![Mozilla HTTP Observatory Grade](https://img.shields.io/mozilla-observatory/grade-score/open-fixture-library.org?publish)](https://developer.mozilla.org/en-US/observatory/analyze?host=open-fixture-library.org)\n[![Beacon](https://img.shields.io/badge/dynamic/json?color=blue&label=Beacon&query=%24.co2&suffix=%20CO%E2%82%82%2Fview&url=https%3A%2F%2Fdigitalbeacon.co%2Fbadge%3Furl%3Dhttps%253A%252F%252Fopen-fixture-library.org&cacheSeconds=604800)](https://digitalbeacon.co/report/open-fixture-library-org)\n\n[<img alt=\"OFL logo\" src=\"https://cdn.rawgit.com/OpenLightingProject/open-fixture-library/master/ui/static/ofl-logo.svg\" width=\"250\" />](ui/static/ofl-logo.svg)\n\nTo use lighting control software like [QLC+](https://www.qlcplus.org/), [DMXControl](https://www.dmxcontrol.org/) or [e:cue](https://www.osram.de/ecue/), you need fixture definition files that describe your lighting hardware. Since one software can usually only understand its own fixture definition format, switching between different programs can be difficult.\n\nThe *Open Fixture Library* tries to solve this problem by collecting fixture definitions and making them downloadable in various formats. Internally, it uses a [JSON format](docs/fixture-format.md) that tries to bundle as much information as possible for all the different output formats.\n\n\n## Contribute without coding\n\nThe easiest way to help: Head over to the online [Fixture Editor](https://open-fixture-library.org/fixture-editor) and add your favorite fixture that is not yet included in our library!\n\nThere are also [other ways you can help without coding](docs/CONTRIBUTING.md#how-you-can-help).\n\n**🙏 Help wanted!** There are [a lot of pull requests](https://github.com/OpenLightingProject/open-fixture-library/pulls?q=is%3Apr+is%3Aopen+label%3Anew-fixture+sort%3Aupdated-desc) for new fixtures that are not yet reviewed and merged. Reviewing them (and maybe fixing smaller issues) helps get this number down and the number of fixtures in OFL up! See the [step-by-step instructions for fixture reviews](docs/CONTRIBUTING.md#fixtures).\n\n\n## Contribute code\n\nSee [CONTRIBUTING.md](docs/CONTRIBUTING.md) and our [Developer Documentation](docs/README.md).\n"
  },
  {
    "path": "cli/build-plugin-data.js",
    "content": "#!/usr/bin/env node\n\nimport { readdir, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { styleText } from 'util';\nimport importJson from '../lib/import-json.js';\n\nconst plugins = {\n  importPlugins: [],\n  exportPlugins: [],\n  data: {},\n};\n\nconst allPreviousVersions = {};\n\nconst pluginDirectoryUrl = new URL('../plugins/', import.meta.url);\n\nconst directoryEntries = await readdir(pluginDirectoryUrl, { withFileTypes: true });\nconst pluginKeys = directoryEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);\n\nfor (const pluginKey of pluginKeys) {\n  plugins.data[pluginKey] = {};\n\n  await readPluginJson(pluginKey);\n  await readPluginImport(pluginKey);\n  await readPluginExport(pluginKey);\n  await readPluginExportTests(pluginKey);\n}\n\nfor (const [key, data] of Object.entries(allPreviousVersions)) {\n  if (key in plugins.data) {\n    plugins.data[key].newPlugin = data.newPlugin;\n  }\n  else {\n    plugins.data[key] = data;\n  }\n}\n\n// sort plugin data object by key\nplugins.data = Object.fromEntries(\n  Object.keys(plugins.data).toSorted().map((key) => [key, plugins.data[key]]),\n);\n\nconst filePath = fileURLToPath(new URL('plugins.json', pluginDirectoryUrl));\n\ntry {\n  await writeFile(filePath, `${JSON.stringify(plugins, null, 2)}\\n`, 'utf-8');\n  console.log(styleText('green', '[Success]'), 'Updated plugin data file', filePath);\n  process.exit(0);\n}\ncatch (error) {\n  console.error(styleText('red', '[Fail]'), 'Could not write plugin data file.', error);\n  process.exit(1);\n}\n\n/**\n * Reads information from the plugin's `plugin.json` file into `plugins` and `allPreviousVersions`.\n * @param {string} pluginKey The plugin key.\n */\nasync function readPluginJson(pluginKey) {\n  try {\n    const pluginJson = await importJson(`${pluginKey}/plugin.json`, pluginDirectoryUrl);\n    plugins.data[pluginKey].name = pluginJson.name;\n\n    if (pluginJson.previousVersions) {\n      for (const [key, name] of Object.entries(pluginJson.previousVersions)) {\n        allPreviousVersions[key] = {\n          name,\n          outdated: true,\n          newPlugin: pluginKey,\n        };\n      }\n    }\n  }\n  catch (error) {\n    console.error(`Plugin ${pluginKey} does not contain a valid plugin.json file:`, error);\n    process.exit(1);\n  }\n}\n\n/**\n * Reads information from the plugin's `import.js` file (if it exists) into `plugins`.\n * @param {string} pluginKey The plugin key.\n */\nasync function readPluginImport(pluginKey) {\n  try {\n    const importPlugin = await import(new URL(`${pluginKey}/import.js`, pluginDirectoryUrl));\n    plugins.importPlugins.push(pluginKey);\n    plugins.data[pluginKey].importPluginVersion = importPlugin.version;\n  }\n  catch (error) {\n    if (error.code === 'ERR_MODULE_NOT_FOUND') {\n      // ignore non-existing file\n      return;\n    }\n\n    console.error(`Import plugin ${pluginKey} could not be parsed:`, error.message);\n    process.exit(1);\n  }\n}\n\n/**\n * Reads information from the plugin's `export.js` file (if it exists) into `plugins`.\n * @param {string} pluginKey The plugin key.\n */\nasync function readPluginExport(pluginKey) {\n  try {\n    const exportPlugin = await import(new URL(`${pluginKey}/export.js`, pluginDirectoryUrl));\n    plugins.exportPlugins.push(pluginKey);\n    plugins.data[pluginKey].exportPluginVersion = exportPlugin.version;\n    plugins.data[pluginKey].exportTests = [];\n  }\n  catch (error) {\n    if (error.code === 'ERR_MODULE_NOT_FOUND') {\n      // ignore non-existing file\n      return;\n    }\n\n    console.error(`Export plugin ${pluginKey} could not be parsed:`, error.message);\n    process.exit(1);\n  }\n}\n\n/**\n * Adds the plugin's export tests (if any) to `plugins`.\n * @param {string} pluginKey The plugin key.\n */\nasync function readPluginExportTests(pluginKey) {\n  try {\n    const exportTestFiles = await readdir(new URL(`${pluginKey}/exportTests/`, pluginDirectoryUrl));\n    for (const test of exportTestFiles) {\n      const testKey = path.basename(test, path.extname(test));\n      plugins.data[pluginKey].exportTests.push(testKey);\n    }\n  }\n  catch (error) {\n    if (error.code === 'ENOENT') {\n      // ignore non-existing directory\n      return;\n    }\n\n    console.error(`Export tests for plugin ${pluginKey} could not be read:`, error.message);\n    process.exit(1);\n  }\n}\n"
  },
  {
    "path": "cli/build-register.js",
    "content": "#!/usr/bin/env node\n\nimport { readdir, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { styleText } from 'util';\nimport importJson from '../lib/import-json.js';\nimport { Register } from '../lib/register.js';\n\nlet register;\nlet manufacturers;\n\nconst fixturesPath = fileURLToPath(new URL('../fixtures/', import.meta.url));\n\ntry {\n  manufacturers = await importJson('../fixtures/manufacturers.json', import.meta.url);\n  register = new Register(manufacturers);\n\n  await addFixturesToRegister();\n}\ncatch (readError) {\n  console.error('Read error:', readError);\n  process.exit(1);\n}\n\nconst registerFilename = path.join(fixturesPath, (process.argv.length === 3 ? process.argv[2] : 'register.json'));\nconst fileContents = `${JSON.stringify(register.getAsSortedObject(), null, 2)}\\n`;\n\ntry {\n  await writeFile(registerFilename, fileContents, 'utf-8');\n  console.log(styleText('green', '[Success]'), 'Updated register file', registerFilename);\n  process.exit(0);\n}\ncatch (error) {\n  console.error(styleText('red', '[Fail]'), 'Could not write register file.', error);\n  process.exit(1);\n}\n\n/**\n * Loop through all manufacturer directories and fixture files and add them to the register.\n */\nasync function addFixturesToRegister() {\n  const directoryEntries = await readdir(fixturesPath, { withFileTypes: true });\n  const manufacturerKeys = directoryEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);\n\n  for (const manufacturerKey of manufacturerKeys) {\n    register.addManufacturer(manufacturerKey, manufacturers[manufacturerKey]);\n\n    const manufacturerDirectory = path.join(fixturesPath, manufacturerKey);\n    const fixtureFiles = await readdir(manufacturerDirectory);\n    for (const filename of fixtureFiles) {\n      if (path.extname(filename) !== '.json') {\n        continue;\n      }\n\n      const fixtureKey = path.basename(filename, '.json');\n      const fixtureData = await importJson(`${manufacturerKey}/${filename}`, fixturesPath);\n\n      if (fixtureData.$schema.endsWith('/fixture-redirect.json')) {\n        const redirectToData = await importJson(`${fixtureData.redirectTo}.json`, fixturesPath);\n\n        register.addFixtureRedirect(manufacturerKey, fixtureKey, fixtureData, redirectToData);\n      }\n      else {\n        register.addFixture(manufacturerKey, fixtureKey, fixtureData);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "cli/build-test-fixtures.js",
    "content": "#!/usr/bin/env node\n\n/**\n * @fileoverview This script generates a set of test fixtures that cover all defined fixture features (while\n * keeping the set as small as possible) and updates tests/test-fixtures.json and tests/test-fixtures.md.\n */\n\nimport { readdir, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { styleText } from 'util';\nimport importJson from '../lib/import-json.js';\nimport { fixtureFromRepository } from '../lib/model.js';\n\nconst fixtureFeaturesDirectoryUrl = new URL('../lib/fixture-features/', import.meta.url);\nconst jsonPath = fileURLToPath(new URL('../tests/test-fixtures.json', import.meta.url));\nconst markdownPath = fileURLToPath(new URL('../tests/test-fixtures.md', import.meta.url));\n\n/**\n * @typedef {object} FixtureFeature\n * @property {string | undefined} id The fixture feature's ID\n * @property {string} name A short name of the fixture feature.\n * @property {string} description A longer description of the fixture feature.\n * @property {(fixture: Fixture) => boolean | Promise<boolean>} hasFeature A function that returns whether a given fixture supports this feature.\n */\n\n/**\n * @typedef {object} FixtureFeatureResult\n * @property {string} man The fixture manufacturer's name.\n * @property {string} key The combined manufacturer/fixture key.\n * @property {string} name The fixture name.\n * @property {string[]} features The IDs of all fixture features that the fixture supports.\n */\n\nconst register = await importJson('../fixtures/register.json', import.meta.url);\n\nconst allFixtureFeatures = await getFixtureFeatures();\nconst featuresUsed = Object.fromEntries(allFixtureFeatures.map((feature) => [feature.id, 0]));// check which features each fixture supports\n\n/** @type {FixtureFeatureResult[]} */\nlet fixtureFeatureResults = [];\n\nfor (const manufacturerFixture of Object.keys(register.filesystem)) {\n  const [manufacturerKey, fixtureKey] = manufacturerFixture.split('/');\n\n  // pre-process data\n  const fixture = await fixtureFromRepository(manufacturerKey, fixtureKey);\n  const fixtureResult = {\n    man: manufacturerKey,\n    key: fixtureKey,\n    name: fixture.name,\n    features: [],\n  };\n\n  // check all features\n  for (const fixtureFeature of allFixtureFeatures) {\n    if (await fixtureFeature.hasFeature(fixture)) {\n      fixtureResult.features.push(fixtureFeature.id);\n      featuresUsed[fixtureFeature.id]++;\n    }\n  }\n\n  fixtureFeatureResults.push(fixtureResult);\n}\n\n// first fixtures are more likely to be filtered out, so we start with the ones with the fewest features\nfixtureFeatureResults.sort((a, b) => {\n  if (a.features.length === b.features.length) {\n    return `${a.man}/${a.key}`.localeCompare(`${b.man}/${b.key}`, 'en');\n  }\n\n  return a.features.length - b.features.length;\n});\n\n// filter out\nfixtureFeatureResults = fixtureFeatureResults.filter((fixture) => {\n  for (const feature of fixture.features) {\n    // this is the only remaining fixture with that feature -> keep it\n    if (featuresUsed[feature] === 1) {\n      return true;\n    }\n  }\n  // has no new features -> filter out\n  for (const feature of fixture.features) {\n    featuresUsed[feature]--;\n  }\n  return false;\n});\n\n// original alphabetic ordering\nfixtureFeatureResults.sort((a, b) => {\n  return `${a.man}/${a.key}`.localeCompare(`${b.man}/${b.key}`, 'en');\n});\n\nconsole.log(styleText('yellow', 'Generated list of test fixtures:'));\nfor (const fixture of fixtureFeatureResults) {\n  console.log(` - ${fixture.man}/${fixture.key}`);\n}\n\ntry {\n  await writeFile(jsonPath, `${JSON.stringify(fixtureFeatureResults, null, 2)}\\n`, 'utf-8');\n  console.log(styleText('green', '[Success]'), `Updated ${jsonPath}`);\n\n  await writeFile(markdownPath, await getMarkdownCode(fixtureFeatureResults, allFixtureFeatures), 'utf-8');\n  console.log(styleText('green', '[Success]'), `Updated ${markdownPath}`);\n}\ncatch (error) {\n  console.error(styleText('red', '[Fail]'), 'Could not write test fixtures file:', error);\n}\n\n/**\n * @returns {Promise<FixtureFeature[]>} A Promise that resolves to an array of all defined fixture features.\n */\nasync function getFixtureFeatures() {\n  const fixtureFeatures = [];\n\n  for (const fileName of await readdir(fixtureFeaturesDirectoryUrl)) {\n    if (path.extname(fileName) !== '.js') {\n      continue;\n    }\n\n    // module exports array of fix features\n    const fixtureFeatureFileUrl = new URL(fileName, fixtureFeaturesDirectoryUrl);\n    const { default: fixtureFeatureFile } = await import(fixtureFeatureFileUrl);\n\n    for (const [index, fixtureFeature] of fixtureFeatureFile.entries()) {\n      // default id\n      if (!('id' in fixtureFeature)) {\n        fixtureFeature.id = path.basename(fileName, '.js');\n        if (fixtureFeatureFile.length > 1) {\n          fixtureFeature.id += `-${index}`;\n        }\n      }\n\n      // check uniqueness of id\n      const featureIdExists = fixtureFeatures.some((feature) => feature.id === fixtureFeature.id);\n      if (featureIdExists) {\n        console.error(styleText('red', '[Error]'), `Fixture feature id '${fixtureFeature.id}' is used multiple times.`);\n        process.exit(1);\n      }\n\n      fixtureFeatures.push(fixtureFeature);\n    }\n  }\n\n  return fixtureFeatures;\n}\n\n/**\n * Generates a markdown table presenting the test fixtures and all fix features.\n * @param {FixtureFeatureResult[]} fixtures The fixture feature results.\n * @param {FixtureFeature[]} fixtureFeatures All fixture features.\n * @returns {Promise<string>} A Promise that resolves to the markdown code to be used in a markdown file.\n */\nasync function getMarkdownCode(fixtures, fixtureFeatures) {\n  const manufacturers = await importJson('../fixtures/manufacturers.json', import.meta.url);\n\n  const mdLines = [\n    '# Test fixtures',\n    '',\n    'See the [fixture feature documentation](../docs/fixture-features.md). This file is automatically',\n    'generated by [`cli/build-test-fixtures.js`](../cli/build-test-fixtures.js).',\n    '',\n    ...fixtures.map(\n      (fixture, index) => `${index + 1}. [*${manufacturers[fixture.man].name}* ${fixture.name}](../fixtures/${fixture.man}/${fixture.key}.json)`,\n    ),\n    '',\n  ];\n\n  // table head\n  const tableHead = ['*Fixture number*', ...fixtures.map((fixture, index) => index + 1)].join(' | ');\n\n  mdLines.push(\n    tableHead,\n    '|-'.repeat(fixtures.length + 1),\n  );\n\n  // table body\n  const footnotes = [];\n  for (const [index, fixtureFeature] of fixtureFeatures.entries()) {\n    let line = `**${fixtureFeature.name}**`;\n\n    if (fixtureFeature.description) {\n      footnotes.push(fixtureFeature.description);\n      const n = footnotes.length;\n      line += ` [<sup>[${n}]</sup>](#user-content-footnote-${n})`;\n    }\n\n    for (const fixture of fixtures) {\n      line += fixture.features.includes(fixtureFeature.id) ? ' | ✅' : ' | ❌';\n    }\n\n    mdLines.push(line);\n\n    // repeat table head\n    if ((index + 1) % 15 === 0) {\n      mdLines.push(tableHead);\n    }\n  }\n\n  // footnotes\n  mdLines.push('', '## Footnotes', '');\n  for (const [index, footnote] of footnotes.entries()) {\n    mdLines.push(`**<a id=\"user-content-footnote-${index + 1}\">[${index + 1}]</a>**: ${footnote}  `);\n  }\n  mdLines.push('');\n\n  return mdLines.join('\\n');\n}\n"
  },
  {
    "path": "cli/debug-env-variables.js",
    "content": "#!/usr/bin/env node\n\nimport { styleText } from 'util';\n\nconst usedVariables = [\n  'ALLOW_SEARCH_INDEXING',\n  'GITHUB_USER_TOKEN',\n  'GITHUB_BROKEN_LINKS_ISSUE_NUMBER',\n  'NODE_ENV',\n  'PORT',\n  'HOST',\n  'WEBSITE_URL',\n  'GITHUB_PR_NUMBER',\n  'GITHUB_PR_HEAD_REF',\n  'GITHUB_PR_BASE_REF',\n  'GITHUB_REPOSITORY',\n  'GITHUB_RUN_ID',\n  'GITHUB_REF',\n];\n\nconsole.log('This scripts lists all environment variables that are used in the Open Fixture Library.\\n');\n\nconsole.log('Process environment variables:');\nprintVariables();\nconsole.log();\n\nawait import('../lib/load-env-file.js');\n\nconsole.log('Environment variables after reading .env:');\nprintVariables();\n\n/**\n * Prints all used environment variables and their values / unset\n */\nfunction printVariables() {\n  for (const key of usedVariables) {\n    const coloredKey = styleText('yellow', key);\n    if (key in process.env) {\n      const coloredValue = styleText('green', process.env[key]);\n      console.log(`${coloredKey}=${coloredValue}`);\n    }\n    else {\n      const unsetLabel = styleText('red', ' is unset');\n      console.log(`${coloredKey}${unsetLabel}`);\n    }\n  }\n}\n"
  },
  {
    "path": "cli/diff-plugin-outputs.js",
    "content": "#!/usr/bin/env node\n\nimport { styleText } from 'util';\nimport minimist from 'minimist';\nimport diffPluginOutputs from '../lib/diff-plugin-outputs.js';\nimport importJson from '../lib/import-json.js';\n\nconst plugins = await importJson('../plugins/plugins.json', import.meta.url);\nconst testFixtures = await importJson('../tests/test-fixtures.json', import.meta.url);\nconst testFixtureKeys = testFixtures.map((fixture) => `${fixture.man}/${fixture.key}`);\n\nconst cliArguments = minimist(process.argv.slice(2), {\n  string: ['p', 'c', 'r'],\n  boolean: ['t', 'h'],\n  alias: { p: 'plugin', c: 'compare-plugin', r: 'ref', t: 'test-fix', h: 'help' },\n  default: { r: 'HEAD' },\n});\ncliArguments.comparePlugin = cliArguments['compare-plugin'];\ncliArguments.testFix = cliArguments['test-fix'];\ncliArguments.fixtures = cliArguments._;\n\nconst scriptName = import.meta.url.split('/').slice(-2).join('/');\nconst exportPlugins = plugins.exportPlugins.join(', ');\n\nconst helpMessage = [\n  'This script exports the given fixtures with the current version of the given plugin and diffs the results',\n  'against the files exported with the comparePlugin at the state of the given Git reference.',\n  'Fixtures have to be declared with the path to its file in the fixtures/ directory.',\n  `Usage: node ${scriptName} -p <plugin-key> [-c <compare-plugin-key>] [-r <git-ref>] [ -t | <fixture> [<more fixtures>] ]`,\n  'Options:',\n  '  --plugin,         -p: Which plugin should be used to output fixtures. Allowed values:',\n  `                        ${exportPlugins}`,\n  '  --compare-plugin, -c: A plugin from the given git reference (may not exist anymore). Defaults to --plugin.',\n  '  --ref,            -r: The Git reference with which the current repo should be compared.',\n  '                        E. g. 02ba13, HEAD~1 or master.',\n  '                        Defaults to HEAD.',\n  '  --test-fix,       -t: Use the test fixtures instead of specifing custom fixtures.',\n  '  --help,           -h: Show this help message.',\n].join('\\n');\n\nif (cliArguments.help) {\n  console.log(helpMessage);\n  process.exit(0);\n}\n\nif (!cliArguments.plugin) {\n  console.error(styleText('red', '[Error]'), 'Plugin has to be specified using --plugin');\n  console.log(helpMessage);\n  process.exit(1);\n}\n\nif (!cliArguments.comparePlugin) {\n  cliArguments.comparePlugin = cliArguments.plugin;\n  cliArguments.c = cliArguments.p;\n}\n\nif (cliArguments.fixtures.length === 0 && !cliArguments.testFix) {\n  console.log(styleText('yellow', '[Warning]'), 'No fixtures specified. See --help for usage.');\n}\n\ndiffPluginOutputs(cliArguments.plugin, cliArguments.comparePlugin, cliArguments.ref, cliArguments.testFix ? testFixtureKeys : cliArguments.fixtures);\n"
  },
  {
    "path": "cli/export-fixture.js",
    "content": "#!/usr/bin/env node\nimport { mkdir, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { styleText } from 'util';\nimport minimist from 'minimist';\nimport importJson from '../lib/import-json.js';\nimport { fixtureFromRepository } from '../lib/model.js';\n\ntry {\n  const cliArguments = minimist(process.argv.slice(2), {\n    string: ['p', 'o'],\n    boolean: ['h', 'a'],\n    alias: { p: 'plugin', h: 'help', a: 'all-fixtures', o: 'output-dir' },\n  });\n\n  await checkCliArguments(cliArguments);\n\n  let fixtures;\n  if (cliArguments.a) {\n    const register = await importJson('../fixtures/register.json', import.meta.url);\n    fixtures = Object.keys(register.filesystem).filter(\n      (fixtureKey) => !('redirectTo' in register.filesystem[fixtureKey]) || register.filesystem[fixtureKey].reason === 'SameAsDifferentBrand',\n    ).map((fixtureKey) => fixtureKey.split('/'));\n  }\n  else {\n    fixtures = cliArguments._.map((relativePath) => {\n      const absolutePath = path.join(process.cwd(), relativePath);\n      return [\n        path.basename(path.dirname(absolutePath)), // man key\n        path.basename(absolutePath, path.extname(absolutePath)), // fix key\n      ];\n    });\n  }\n\n  const outDirectory = cliArguments.o ? path.resolve(process.cwd(), cliArguments.o) : null;\n\n  const plugin = await import(`../plugins/${cliArguments.plugin}/export.js`);\n  const files = await plugin.exportFixtures(\n    await Promise.all(fixtures.map(\n      ([manufacturer, fixture]) => fixtureFromRepository(manufacturer, fixture),\n    )),\n    {\n      baseDirectory: fileURLToPath(new URL('../', import.meta.url)),\n      date: new Date(),\n    },\n  );\n  for (const file of files) {\n    if (cliArguments.o) {\n      const filePath = path.join(outDirectory, file.name);\n      await mkdir(path.dirname(filePath), { recursive: true });\n      await writeFile(filePath, file.content);\n      console.log(`Created file ${filePath}`);\n    }\n    else {\n      console.log();\n      console.log(styleText('yellow', `File name: '${file.name}'`));\n      console.log(file.content);\n    }\n  }\n}\ncatch (error) {\n  console.error(styleText('red', '[Error]'), 'Exporting failed:', error);\n  process.exit(1);\n}\n\n/**\n * @param {Record<string, unknown>} cliArguments Command line interface arguments parsed by minimist.\n */\nasync function checkCliArguments(cliArguments) {\n  const helpMessage = [\n    `Usage: ${process.argv[1]} -p <plugin name> [ -a | <fixture> [<more fixtures>] ]`,\n    'Options:',\n    '  --plugin,       -p: Which plugin should be used to export fixtures.',\n    '                      E. g. ecue or qlcplus',\n    '  --all-fixtures, -a: Use all fixtures from register',\n    '  --output-dir,   -o: If set, save outputted files in this directory',\n    '                      instead of printing the contents in the console',\n    '  --help,         -h: Show this help message.',\n  ].join('\\n');\n\n  if (cliArguments.help) {\n    console.log(helpMessage);\n    process.exit(0);\n  }\n\n  if (!cliArguments.plugin) {\n    console.error(styleText('red', '[Error]'), 'No plugin specified. See --help for usage.');\n    process.exit(1);\n  }\n\n  if (cliArguments._.length === 0 && !cliArguments.a) {\n    console.error(styleText('red', '[Error]'), 'No fixtures specified. See --help for usage.');\n    process.exit(1);\n  }\n\n  const plugins = await importJson('../plugins/plugins.json', import.meta.url);\n\n  if (!plugins.exportPlugins.includes(cliArguments.plugin)) {\n    console.error(styleText('red', '[Error]'), `Plugin '${cliArguments.plugin}' does not exist or does not support exporting.\\n\\navailable plugins:`, plugins.exportPlugins.join(', '));\n    process.exit(1);\n  }\n}\n"
  },
  {
    "path": "cli/import-fixture.js",
    "content": "#!/usr/bin/env node\n\nimport { readFile } from 'fs/promises';\nimport minimist from 'minimist';\nimport createPullRequest from '../lib/create-github-pr.js';\nimport fixtureJsonStringify from '../lib/fixture-json-stringify.js';\nimport importJson from '../lib/import-json.js';\nimport { checkFixture } from '../tests/fixture-valid.js';\n/** @import { FixtureCreateResult } from '../lib/types.js' */\n\nconst cliArguments = minimist(process.argv.slice(2), {\n  string: ['p', 'a'],\n  boolean: 'c',\n  alias: {\n    a: 'author-name',\n    p: 'plugin',\n    c: 'create-pull-request',\n  },\n});\n\nawait checkCliArguments();\n\nconst filename = cliArguments._[0];\n\ntry {\n  const buffer = await readFile(filename);\n\n  const plugin = await import(`../plugins/${cliArguments.plugin}/import.js`);\n  const { manufacturers, fixtures, warnings } = await plugin.importFixtures(buffer, filename, cliArguments['author-name']);\n\n  /** @type {FixtureCreateResult} */\n  const result = {\n    manufacturers,\n    fixtures,\n    warnings,\n    errors: {},\n  };\n\n  for (const key of Object.keys(result.fixtures)) {\n    const [manufacturerKey, fixtureKey] = key.split('/');\n\n    const checkResult = await checkFixture(manufacturerKey, fixtureKey, result.fixtures[key]);\n\n    result.warnings[key].push(...checkResult.warnings);\n    result.errors[key] = checkResult.errors;\n  }\n\n  if (cliArguments['create-pull-request']) {\n    try {\n      const pullRequestUrl = await createPullRequest(result);\n      console.log(`URL: ${pullRequestUrl}`);\n    }\n    catch (error) {\n      console.log(fixtureJsonStringify(result));\n      console.error(`Error creating pull request: ${error.message}`);\n    }\n  }\n  else {\n    console.log(fixtureJsonStringify(result));\n  }\n}\ncatch (error) {\n  console.error(`Error parsing '${filename}':`);\n  console.error(error);\n  process.exit(1);\n}\n\n/**\n * Checks the command line interface arguments parsed by minimist.\n */\nasync function checkCliArguments() {\n  const plugins = await importJson('../plugins/plugins.json', import.meta.url);\n\n  if (cliArguments._.length !== 1 || !plugins.importPlugins.includes(cliArguments.plugin) || !cliArguments['author-name']) {\n    const importPlugins = plugins.importPlugins.join(', ');\n    console.error(`Usage: ${process.argv[1]} -p <plugin> -a <author name> [--create-pull-request] <filename>\\n\\navailable plugins: ${importPlugins}`);\n    process.exit(1);\n  }\n}\n"
  },
  {
    "path": "cli/run-export-test.js",
    "content": "#!/usr/bin/env node\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { styleText } from 'util';\nimport minimist from 'minimist';\nimport importJson from '../lib/import-json.js';\nimport { fixtureFromFile, fixtureFromRepository } from '../lib/model.js';\n\nconst failLabel = styleText('red', '[FAIL]');\nconst passLabel = styleText('green', '[PASS]');\n\ntry {\n  const plugins = await importJson('../plugins/plugins.json', import.meta.url);\n  const testFixtures = await importJson('../tests/test-fixtures.json', import.meta.url);\n\n  const cliArguments = minimist(process.argv.slice(2), {\n    string: ['p'],\n    boolean: ['h'],\n    alias: { p: 'plugin', h: 'help' },\n  });\n\n  const scriptName = import.meta.url.split('/').pop();\n\n  const helpMessage = [\n    'Run the plugin\\'s export tests against the specified fixtures',\n    '(or the test fixtures, if no fixtures are specified).',\n    `Usage: node ${scriptName} -p <plugin> [ <fixtures> ]`,\n    'Options:',\n    '  --plugin,   -p: Key of the plugin whose export tests should be called',\n    '  --help,     -h: Show this help message.',\n  ].join('\\n');\n\n  if (cliArguments.help) {\n    console.log(helpMessage);\n    process.exit(0);\n  }\n\n  if (!cliArguments.plugin) {\n    console.error(styleText('red', '[Error]'), 'Plugin has to be specified using --plugin');\n    console.log(helpMessage);\n    process.exit(1);\n  }\n\n  if (!plugins.exportPlugins.includes(cliArguments.plugin)) {\n    console.error(styleText('red', '[Error]'), `Plugin '${cliArguments.plugin}' is not a valid export plugin.\\nAvailable export plugins:`, plugins.exportPlugins.join(', '));\n    process.exit(1);\n  }\n\n  const pluginData = plugins.data[cliArguments.plugin];\n  if (pluginData.exportTests.length === 0) {\n    console.log(styleText('green', '[PASS]'), `Plugin '${cliArguments.plugin}' has no export tests.`);\n    process.exit(0);\n  }\n\n  const fixtures = cliArguments._.length === 0\n    ? testFixtures.map((fixture) => fixtureFromRepository(fixture.man, fixture.key))\n    : cliArguments._.map((relativePath) => fixtureFromFile(path.join(process.cwd(), relativePath)));\n\n  const exportPlugin = await import(`../plugins/${cliArguments.plugin}/export.js`);\n\n  const files = await exportPlugin.exportFixtures(\n    await Promise.all(fixtures),\n    {\n      baseDirectory: fileURLToPath(new URL('../', import.meta.url)),\n      date: new Date(),\n    },\n  );\n\n  await Promise.all(pluginData.exportTests.map(async (testKey) => {\n    const { default: exportTest } = await import(`../plugins/${cliArguments.plugin}/exportTests/${testKey}.js`);\n\n    const outputPerFile = await Promise.all(files.map(async (file) => {\n      try {\n        await exportTest(file, files);\n        return `${passLabel} ${file.name}`;\n      }\n      catch (testError) {\n        const errors = Array.isArray(testError) ? testError : [testError];\n\n        return [\n          `${failLabel} ${file.name}`,\n          ...errors.map((error) => `- ${error}`),\n        ].join('\\n');\n      }\n    }));\n\n    console.log();\n    console.log(styleText('yellow', `Test ${testKey}`));\n    console.log(outputPerFile.join('\\n'));\n  }));\n}\ncatch (error) {\n  console.error(styleText('red', '[Error]'), 'Exporting failed:', error);\n  process.exit(1);\n}\n"
  },
  {
    "path": "docs/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at flo@open-fixture-library.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]\n\n[homepage]: https://contributor-covenant.org\n[version]: https://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "docs/CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nWe believe in the power of open source development and want to encourage everyone to contribute to this project. This document should help new developers and documents our coding workflow. If there are any questions left, don't hesitate to [open a new issue](https://github.com/OpenLightingProject/open-fixture-library/issues/new) explaining that you haven't found the information in the docs.\n\n## Developer vibes\n\nPlease keep being friendly and don't troll. See our [Code of Conduct](CODE_OF_CONDUCT.md) for more information on this.\n\n## Issues\n\nYou have an idea about a new feature or you spotted a mistake? Feel free to create an [issue](https://github.com/OpenLightingProject/open-fixture-library/issues) in which you describe the problem / the feature requirements. Please try to find similar issues first though, and add your information there to keep it organized.\n\nAs soon as an issue is assigned to somebody, it means that this person is responsible for fixing it.\n\n## How you can help\n\n### Fixtures\n\n* **Add new fixtures**  \n  Either add fixtures via the online [Fixture Editor](https://open-fixture-library.org/fixture-editor) or by manually writing a [fixture format JSON](fixture-format.md).\n\n* **Answer questions in existing fixtures**  \n  Go through fixtures you know on the [website](https://open-fixture-library.org/manufacturers) and look for yellow \"Help wanted\" boxes with questions you can answer.\n\n* **Review fixtures that are not yet merged**  \n  These are the steps that take the longest when reviewing a fixture:\n\n  > 1. Checking whether at least 3 links are present. Otherwise, finding suitable links.\n  >     - link to a manual PDF containing all DMX modes\n  >     - link to a product page on the official manufacturer website\n  >     - link to a YouTube or Vimeo video that showcases or explains the fixture\n  > 2. Checking whether all DMX modes from the manual are included in the fixture definition.  \n  > 3. Checking whether all DMX modes' channels from the manual are included in the fixture definition.  \n  > 4. Checking whether all DMX channels' capabilities from the manual are included in the fixture definition.\n\n  If you could go through some [PRs with the `new-fixture` label](https://github.com/OpenLightingProject/open-fixture-library/pulls?q=is%3Apr+is%3Aopen+label%3Anew-fixture) and comment on them with the results of those checks, that would help immensely. Thank you already :)\n\n  For the fixtures passing these tests, these are some common tasks that often need to be fixed:\n\n  - replace capability type `StrobeSpeed` with `ShutterStrobe` where that one fits better\n  - replace capability type `Generic` with `Maintenance` where that one fits better\n  - rename modes that have no name in the manual to the usual `5-channel`/`5ch` format\n  - link to an English manual / product page (if one exists) instead of one in another language\n\n  Pull requests with these fixes against the original fixture pull requests (see e.g. [#2023](https://github.com/OpenLightingProject/open-fixture-library/pull/2023)) are highly appreciated!\n\n* **Add links and colors to existing fixtures**  \n  See [#578](https://github.com/OpenLightingProject/open-fixture-library/issues/578) and [#723](https://github.com/OpenLightingProject/open-fixture-library/issues/723). There are also some broken links (see [#999](https://github.com/OpenLightingProject/open-fixture-library/issues/999)), maybe you can find some alternative links to replace them.\n\n### Code\n\n* **Work on easy issues**  \n  Browse the [`good-first-issues` label](https://github.com/OpenLightingProject/open-fixture-library/issues?q=is:open+is:issue+label:%22good+first+issue%22) to find some easy tasks.\n\n* **Implement your own idea**  \n  Please create a new issue first if it's a bigger change.\n\n* **Create new import/export plugins**  \n  This is a bit more involved. See the [list of new plugins](https://github.com/OpenLightingProject/open-fixture-library/issues?q=is%3Aissue+is%3Aopen+label%3Anew-plugin) for inspiration. Use existing plugins as reference and look at the [plugin documentation](plugins.md).\n\n* **Improve the [documentation](README.md)**  \n  Especially after you have made other changes, there is likely something you've been missing in the documentation. Help others find it there!\n\n## Local installation\n\nAfter [forking](https://help.github.com/articles/fork-a-repo/) the repository, follow the [GitHub flow](https://guides.github.com/introduction/flow/) to implement your changes.\n\nYou can also create a (draft) pull request if you're not done yet to involve the reviewers into the development process and get help if you're stuck.\n\nSee [README.md](README.md#local-installation) for how to setup and test run the code locally.\n\n## Code style\n\nWe always aim to have clear, readable code. So please try to respect these principles:\n\n* Document every new function with [JSDoc](https://jsdoc.app/about-getting-started.html)\n* Use [self-describing variable names](https://wiki.c2.com/?GoodVariableNames) and prefer constant variables over literal values without explanation\n* Prefer code readability over [micro-optimisation](https://softwareengineering.stackexchange.com/questions/99445/is-micro-optimisation-important-when-coding)\n* Use JavaScript features that improve code readability, for example:\n  - Prefer [Array iteration methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Instance_methods) (like [`map(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), [`filter(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), [`some(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some), [`every(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every), [`find(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)) with arrow functions over loops\n  - Always use [template strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (backticks instead of single or double quotes: ``const str = `My name is ${name}.`;``) as [they are strictly better strings](https://ponyfoo.com/articles/template-literals-strictly-better-strings) and make string concatenation (`const str = 'My name is ' + name + '.';`) more readable\n* Try to make a piece of code not too complex. That is, if a function contains lots of ifs and for-loops, extract some parts into helper functions. (For example, the `checkFixture()` function calls `checkPhysical()` and `checkChannels()`, `checkChannel()` calls `checkCapabilities()`, etc.)\n\nWe automatically check code style using [ESLint](https://eslint.org/). Maybe your IDE supports ESLint highlighting (there's a good [extension for VSCode](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)) – this helps spotting bad code style as quickly as possible.\n\n## Developer tips\n\n* To understand how OFL works, read the [Documentation Overview](README.md) and its related pages. We try to document every part of our software.\n* Run [tests](testing.md) in the `tests/` directory locally before pushing – that's faster than waiting for the automated GitHub Actions tests in pull requests.\n* Run `npm run build` to be sure that auto-generated contents are up-to-date.\n"
  },
  {
    "path": "docs/README.md",
    "content": "# Documentation Overview\n\nThis is the developer documentation for the *Open Fixture Library*. Please follow links in the folder structure below to get more information on a specific topic.\n\n## Repository folder structure\n\n* `cli/` – Useful scripts to be called from the command line\n* `docs/` – Documentation (*you are here!*)\n* `fixtures/` – Repository of our [fixture definitions](fixture-format.md)\n* `lib/` – Reusable modules used in the project\n  - `fixture-features/` – [Fixture features](fixture-features.md), special fixture characteristics used to determine a set of test fixtures\n  - `model/` – Classes of the [fixture model](fixture-model.md) that help ease processing fixture data (see the [model API reference](model-api.md))\n* `plugins/` – [Plugins](plugins.md) for export / import to / from other software's fixture formats\n* `resources/` – Resources (e.g. [gobos](fixture-format.md#gobo-resources)) that fixtures can use\n* `schemas/` – Schemas for the [fixture definitions](fixture-format.md#schema)\n* `server/` – Load balancer config and auto-deploy script for everyone interested\n* `tests/` – [Unit tests](testing.md), many of them run automatically in GitHub Actions\n  - `github/` – Special kind of tests which shouldn't be called manually and create comments in GitHub pull requests\n* `ui/` – Everything related to the [UI / Website](ui.md) (see docs there for subfolders)\n* `tmp/` – Temporary files autogenerated by tests. Safe to delete and not indexed by Git.\n\n## Local installation\n\n### Linux / macOS\n\nMake sure you have these dependencies installed:\n\n* `git`\n* [Node.js](https://nodejs.org/en/download/package-manager/)\n\nThen run\n\n```sh\ngit clone https://github.com/OpenLightingProject/open-fixture-library.git\ncd open-fixture-library\nnpm install\nnpm run build\n```\n\nContinue with [UI docs](ui.md).\n\n### Windows\n\nMake sure you have these dependencies installed:\n\n* [Git](https://gitforwindows.org/)\n* [Node.js](https://nodejs.org/en/download/)\n  * On the *Tools for Native Modules* page, activate the checkbox *Automatically install the necessary tools. [...]*\n\nChoose a project path that only contains ASCII characters and no spaces. Open a Terminal and run\n\n```bat\ngit clone https://github.com/OpenLightingProject/open-fixture-library.git\ncd open-fixture-library\nnpm install\nnpm run build\n```\n\nContinue with [UI docs](ui.md).\n\n### Dev Container\n\nMake sure you have these dependencies installed:\n\n* [Git](https://git-scm.com/downloads)\n* [Docker Desktop](https://www.docker.com/products/docker-desktop/)\n  * **Windows-only:** [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) + [WSL integration](https://docs.docker.com/desktop/wsl/) in Docker Desktop enabled\n* [VS Code](https://code.visualstudio.com/Download)\n  * [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension installed\n  * **Windows-only:** [WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) extension installed\n\nOpen a terminal and run:\n\n```sh\ngit clone https://github.com/OpenLightingProject/open-fixture-library.git\ncode open-fixture-library\n```\n\nIn VS Code, select <kbd>F1</kbd> -> *Dev Containers: Reopen in Container*, which reopens the repository in a container and runs `npm install`.\n\nOpen a terminal in VS Code and run:\n\n```sh\nnpm run build\n```\n\nContinue with [UI docs](ui.md).\n\n## Contributing\n\nPlease see [`CONTRIBUTING.md`](CONTRIBUTING.md).\n\n## Environment variables\n\nSee [`environment-variables.md`](environment-variables.md).\n"
  },
  {
    "path": "docs/capability-types.md",
    "content": "This is a full list of capability types with their properties, entities and units. See the [general information about capabilities](fixture-format.md#capabilities).\n\n\n### Possible entities and keywords\n\nMost type-specific properties refer to one of the following entities, which allow different units. \n\nTo make common percentage values more readable, one can use specific keywords to replace them. For example, `\"speed\": \"fast\"` has the same effect as `\"speed\": \"100%\"`.\n\n| Entity           | Allowed Units    | `-100%`      | `-1%`        | `0%`          | `1%`                       | `100%`\n| -                | -                | -            | -            | -             | -                          | -\n| Speed            | `Hz`, `bpm`, `%` | fast reverse | slow reverse | stop          | slow                       | fast\n| RotationSpeed    | `Hz`, `rpm`, `%` | fast CCW     | slow CCW     | stop          | slow CW                    | fast CW\n| Time             | `s`, `ms`, `%`   | –            | –            | instant       | short                      | long\n| Distance         | `m`, `%`         | –            | –            | –             | near                       | far\n| Brightness       | `lm`, `%`        | –            | –            | off           | dark                       | bright\n| ColorTemperature | `K`, `%`         | warm / CTO   | –            | default       | –                          | cold / CTB\n| FogOutput        | `m^3/min`, `%`   | –            | –            | off           | weak                       | strong\n| RotationAngle    | `deg`, `%`       | –            | –            | –             | –                          | –\n| BeamAngle        | `deg`, `%`       | –            | –            | closed        | narrow                     | wide\n| HorizontalAngle  | `deg`, `%`       | left         | –            | center        | –                          | right\n| VerticalAngle    | `deg`, `%`       | top          | –            | center        | –                          | bottom\n| SwingAngle       | `deg`, `%`       | –            | –            | off           | narrow                     | wide\n| Parameter        | (no unit), `%`   | –            | –            | off / instant | low / slow / small / short | high / fast / big / long\n| SlotNumber       | (no unit)        | –            | –            | –             | –                          | –\n| Percent          | `%`              | –            | –            | off           | low                        | high\n| Insertion        | `%`              | –            | –            | out           | –                          | in\n| IrisPercent      | `%`              | –            | –            | closed        | –                          | open\n\n\n### Possible capability types\n\n**Table of contents**\n\n* [NoFunction](#no-function)\n* [ShutterStrobe](#shutter-strobe) / [StrobeSpeed](#strobe-speed) / [StrobeDuration](#strobe-duration)\n* [Intensity](#intensity)\n* [ColorIntensity](#color-intensity)\n* [ColorPreset](#color-preset)\n* [ColorTemperature](#color-temperature)\n* [Pan](#pan) / [PanContinuous](#pan-continuous)\n* [Tilt](#tilt) / [TiltContinuous](#tilt-continuous)\n* [PanTiltSpeed](#pan-tilt-speed)\n* [WheelSlot](#wheel-slot) / [WheelShake](#wheel-shake) / [WheelSlotRotation](#wheel-slot-rotation) / [WheelRotation](#wheel-rotation)\n* [Effect](#effect) / [EffectSpeed](#effect-speed) / [EffectDuration](#effect-duration) / [EffectParameter](#effect-parameter)\n* [SoundSensitivity](#sound-sensitivity)\n* [BeamAngle](#beam-angle) / [BeamPosition](#beam-position)\n* [Focus](#focus)\n* [Zoom](#zoom)\n* [Iris](#iris) / [IrisEffect](#iris-effect)\n* [Frost](#frost) / [FrostEffect](#frost-effect)\n* [Prism](#prism) / [PrismRotation](#prism-rotation)\n* [BladeInsertion](#blade-insertion)\n / [BladeRotation](#blade-rotation) / [BladeSystemRotation](#blade-system-rotation)\n* [Fog](#fog) / [FogOutput](#fog-output) / [FogType](#fog-type)\n* Generic types: [Rotation](#rotation) / [Speed](#speed) / [Time](#time) / [Maintenance](#maintenance) / [Generic](#generic)\n\n\n<table>\n<thead>\n<tr>\n  <th scope=\"col\">Capability type</th>\n  <th scope=\"col\">Property</th>\n  <th scope=\"col\">Possible values</th>\n  <th scope=\"col\">Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"no-function\">\n    <img src=\"../ui/assets/icons/fixture/no-function.svg\" />\n    NoFunction\n  </th>\n  <td valign=\"top\" colspan=\"3\">No type-specific properties.</td>\n</tr>\n  <th valign=\"top\" scope=\"row\" id=\"shutter-strobe\" rowspan=\"5\">\n    <img src=\"../ui/assets/icons/fixture/shutter.svg\" />\n    <img src=\"../ui/assets/icons/fixture/strobe.svg\" />\n    ShutterStrobe\n  </th>\n  <td valign=\"top\">shutterEffect<br><sub>🌟 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\"><code>Open</code>, <code>Closed</code>, <code>Strobe</code>, <code>Pulse</code>, <code>RampUp</code>, <code>RampDown</code>, <code>RampUpDown</code>, <code>Lightning</code>, <code>Spikes</code>, <code>Burst</code></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">soundControlled<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></td>\n  <td valign=\"top\">Entity <em>Boolean</em></td>\n  <td valign=\"top\">Defaults to <code>false</code></td>\n</tr>\n<tr>\n  <td valign=\"top\">speed<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">duration<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Time</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">randomTiming<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></td>\n  <td valign=\"top\">Entity <em>Boolean</em></td>\n  <td valign=\"top\">Defaults to <code>false</code></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"strobe-speed\">\n    <img src=\"../ui/assets/icons/fixture/speed.svg\" />\n    StrobeSpeed\n  </th>\n  <td valign=\"top\">speed<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td valign=\"top\">global, doesn't activate strobe directly</td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"strobe-duration\">\n    <img src=\"../ui/assets/icons/fixture/speed.svg\" />\n    StrobeDuration\n  </th>\n  <td valign=\"top\">duration<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Time</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"intensity\">\n    <img src=\"../ui/assets/icons/fixture/dimmer.svg\" />\n    Intensity\n  </th>\n  <td valign=\"top\">brightness<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Brightness</em></td>\n  <td valign=\"top\">Defaults to <code>brightnessStart: \"off\", brightnessEnd: \"bright\"</code></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"color-intensity\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/dimmer.svg\" />\n    ColorIntensity\n  </th>\n  <td valign=\"top\">color<br><sub>🌟 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\">one of our predefined Single Colors:\n    <code>Red</code>, <code>Green</code>, <code>Blue</code>, <code>Cyan</code>, <code>Magenta</code>, <code>Yellow</code>, <code>Amber</code>, <code>White</code>, <code>Warm White</code>, <code>Cold White</code>, <code>UV</code>, <code>Lime</code>, <code>Indigo</code>\n  </td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">brightness<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Brightness</em></td>\n  <td valign=\"top\">Defaults to <code>brightnessStart: \"off\", brightnessEnd: \"bright\"</code></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"color-preset\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/color-changer.svg\" />\n    ColorPreset\n  </th>\n  <td valign=\"top\">colors<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">array of individual color beams as hex code</td>\n  <td valign=\"top\"><a href=\"#property-colors\">see footnote <em>colors</em></a></td>\n</tr>\n<tr>\n  <td valign=\"top\">colorTemperature<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>ColorTemperature</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"color-temperature\">\n    <img src=\"../ui/assets/icons/fixture/color-temperature.svg\" />\n    ColorTemperature\n  </th>\n  <td valign=\"top\">colorTemperature<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>ColorTemperature</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"pan\">\n    <img src=\"../ui/assets/icons/fixture/pan.svg\" />\n    Pan\n  </th>\n  <td valign=\"top\">angle<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"pan-continuous\">\n    <img src=\"../ui/assets/icons/fixture/pan-continuous-cw.svg\" />\n    PanContinuous\n  </th>\n  <td valign=\"top\">speed<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationSpeed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"tilt\">\n    <img src=\"../ui/assets/icons/fixture/tilt.svg\" />\n    Tilt\n  </th>\n  <td valign=\"top\">angle<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"tilt-continuous\">\n    <img src=\"../ui/assets/icons/fixture/tilt-continuous-cw.svg\" />\n    TiltContinuous\n  </th>\n  <td valign=\"top\">speed<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationSpeed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"pan-tilt-speed\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/speed.svg\" />\n    PanTiltSpeed\n  </th>\n  <td valign=\"top\">speed<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td rowspan=\"2\">either <em>speed</em> or <em>duration</em> is allowed</td>\n</tr>\n<tr>\n  <td valign=\"top\">duration<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>Time</em></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"wheel-slot\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/gobo.svg\" />\n    WheelSlot\n  </th>\n  <td valign=\"top\">wheel<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\">Wheel name</td>\n  <td valign=\"top\">Defaults to channel name</td>\n</tr>\n<tr>\n  <td valign=\"top\">slotNumber<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>SlotNumber</em></td>\n  <td valign=\"top\"><a href=\"#property-slotnumber\">see footnote <em>slotNumber</em></a></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"wheel-shake\" rowspan=\"5\">\n    <img src=\"../ui/assets/icons/fixture/wheel-shake.svg\" />\n    <img src=\"../ui/assets/icons/fixture/slot-shake.svg\" />\n    WheelShake\n  </th>\n  <td valign=\"top\">isShaking<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\"><code>wheel</code> or <code>slot</code></td>\n  <td valign=\"top\">Defaults to <code>wheel</code>.</td>\n</tr>\n<tr>\n  <td valign=\"top\">wheel<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\">Wheel name or array of wheel names</td>\n  <td valign=\"top\">Defaults to channel name. Array not allowed when <em>slotNumber</em> is set.</td>\n</tr>\n<tr>\n  <td valign=\"top\">slotNumber<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>SlotNumber</em></td>\n  <td valign=\"top\"><a href=\"#property-slotnumber\">see footnote <em>slotNumber</em></a></td>\n</tr>\n<tr>\n  <td valign=\"top\">shakeSpeed<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">shakeAngle<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>SwingAngle</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"wheel-slot-rotation\" rowspan=\"4\">\n    <img src=\"../ui/assets/icons/fixture/rotation-cw.svg\" />\n    WheelSlotRotation\n  </th>\n  <td valign=\"top\">wheel<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\">Wheel name or array of wheel names</td>\n  <td valign=\"top\">Defaults to channel name. Array not allowed when <em>slotNumber</em> is set.</td>\n</tr>\n<tr>\n  <td valign=\"top\">slotNumber<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>SlotNumber</em></td>\n  <td valign=\"top\"><a href=\"#property-slotnumber\">see footnote <em>slotNumber</em></a></td>\n</tr>\n<tr>\n  <td valign=\"top\">speed<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationSpeed</em></td>\n  <td rowspan=\"2\">either <em>speed</em> or <em>angle</em> is allowed</td>\n</tr>\n<tr>\n  <td valign=\"top\">angle<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"wheel-rotation\" rowspan=\"3\">\n    <img src=\"../ui/assets/icons/fixture/rotation-cw.svg\" />\n    WheelRotation\n  </th>\n  <td valign=\"top\">wheel<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\">Wheel name or array of wheel names</td>\n  <td valign=\"top\">Defaults to channel name.</td>\n</tr>\n<tr>\n  <td valign=\"top\">speed<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationSpeed</em></td>\n  <td rowspan=\"2\">either <em>speed</em> or <em>angle</em> is allowed</td>\n</tr>\n<tr>\n  <td valign=\"top\">angle<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"effect\" rowspan=\"7\">\n    <img src=\"../ui/assets/icons/fixture/effect.svg\" />\n    Effect\n  </th>\n  <td valign=\"top\">effectName<br><sub>🆚 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\">Free text describing the effect</td>\n  <td rowspan=\"2\">either <em>effectName</em> or <em>effectPreset</em> is allowed</td>\n</tr>\n<tr>\n  <td valign=\"top\">effectPreset<br><sub>🆚 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\"><code>ColorJump</code> or <code>ColorFade</code></td>\n</tr>\n<tr>\n  <td valign=\"top\">speed<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">duration<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Time</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">parameter<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Parameter</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">soundControlled<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></td>\n  <td valign=\"top\">Entity <em>Boolean</em></td>\n  <td valign=\"top\">Defaults to <code>false</code></td>\n</tr>\n<tr>\n  <td valign=\"top\">soundSensitivity<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Percent</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"beam-angle\">\n    <img src=\"../ui/assets/icons/fixture/beam-angle.svg\" />\n    BeamAngle\n  </th>\n  <td valign=\"top\">angle<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>BeamAngle</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"beam-position\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/beam-position.svg\" />\n    BeamPosition\n  </th>\n  <td valign=\"top\">horizontalAngle<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>HorizontalAngle</em></td>\n  <td valign=\"top\" rowspan=\"2\">at least one of <em>horizontalAngle</em> or <em>verticalAngle</em> is required</td>\n</tr>\n<tr>\n  <td valign=\"top\">verticalAngle<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>VerticalAngle</em></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"effect-speed\">\n    <img src=\"../ui/assets/icons/fixture/speed.svg\" />\n    EffectSpeed\n  </th>\n  <td valign=\"top\">speed<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"effect-duration\">\n    <img src=\"../ui/assets/icons/fixture/speed.svg\" />\n    EffectDuration\n  </th>\n  <td valign=\"top\">duration<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Time</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"effect-parameter\">\n    <img src=\"../ui/assets/icons/fixture/effect-parameter.svg\" />\n    EffectParameter\n  </th>\n  <td valign=\"top\">parameter<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Parameter</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"sound-sensitivity\">\n    <img src=\"../ui/assets/icons/fixture/sound-sensitivity.svg\" />\n    SoundSensitivity\n  </th>\n  <td valign=\"top\">soundSensitivity<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Percent</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"focus\">\n    <img src=\"../ui/assets/icons/fixture/focus.svg\" />\n    Focus\n  </th>\n  <td valign=\"top\">distance<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Distance</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"zoom\">\n    <img src=\"../ui/assets/icons/fixture/zoom.svg\" />\n    Zoom\n  </th>\n  <td valign=\"top\">angle<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>BeamAngle</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"iris\">\n    <img src=\"../ui/assets/icons/fixture/iris.svg\" />\n    Iris\n  </th>\n  <td valign=\"top\">openPercent<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>IrisPercent</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"iris-effect\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/iris.svg\" />\n    IrisEffect\n  </th>\n  <td valign=\"top\">effectName<br><sub>🌟 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\">Free text describing the effect</td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">speed<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"frost\">\n    <img src=\"../ui/assets/icons/fixture/frost.svg\" />\n    Frost\n  </th>\n  <td valign=\"top\">frostIntensity<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Percent</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"frost-effect\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/frost.svg\" />\n    FrostEffect\n  </th>\n  <td valign=\"top\">effectName<br><sub>🌟 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\">Free text describing the effect</td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">speed<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"prism\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/prism.svg\" />\n    Prism\n  </th>\n  <td valign=\"top\">speed<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>RotationSpeed</em></td>\n  <td rowspan=\"2\">activates fixture's prism; either <em>speed</em> or <em>angle</em> is allowed</td>\n</tr>\n<tr>\n  <td valign=\"top\">angle<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"prism-rotation\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/rotation-cw.svg\" />\n    PrismRotation\n  </th>\n  <td valign=\"top\">speed<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationSpeed</em></td>\n  <td rowspan=\"2\">doesn't activate prism directly; either <em>speed</em> or <em>angle</em> is allowed</td>\n</tr>\n<tr>\n  <td valign=\"top\">angle<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"blade-insertion\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/blade-insertion.svg\" />\n    BladeInsertion\n  </th>\n  <td valign=\"top\">blade<br><sub>🌟 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\"><code>Top</code>, <code>Right</code>, <code>Bottom</code>, <code>Left</code> or a number if the position is unknown</td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">insertion<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Insertion</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"blade-rotation\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/rotation-cw.svg\" />\n    BladeRotation\n  </th>\n  <td valign=\"top\">blade<br><sub>🌟 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\"><code>Top</code>, <code>Right</code>, <code>Bottom</code>, <code>Left</code> or a number if the position is unknown</td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">angle<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"blade-system-rotation\">\n    <img src=\"../ui/assets/icons/fixture/rotation-cw.svg\" />\n    BladeSystemRotation\n  </th>\n  <td valign=\"top\">angle<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"fog\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/smoke.svg\" />\n    <img src=\"../ui/assets/icons/fixture/hazer.svg\" />\n    Fog\n  </th>\n  <td valign=\"top\">fogType<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\"><code>Fog</code> or <code>Haze</code></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">fogOutput<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>FogOutput</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"fog-output\">\n    <img src=\"../ui/assets/icons/fixture/smoke.svg\" />\n    FogOutput\n  </th>\n  <td valign=\"top\">fogOutput<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>FogOutput</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"fog-type\">\n    <img src=\"../ui/assets/icons/fixture/smoke.svg\" />\n    <img src=\"../ui/assets/icons/fixture/hazer.svg\" />\n    FogType\n  </th>\n  <td valign=\"top\">fogType<br><sub>🌟 required</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></sub></td>\n  <td valign=\"top\"><code>Fog</code> or <code>Haze</code></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"rotation\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/rotation-cw.svg\" />\n    Rotation\n  </th>\n  <td valign=\"top\">speed<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationSpeed</em></td>\n  <td rowspan=\"2\">either <em>speed</em> or <em>angle</em> is allowed</td>\n</tr>\n<tr>\n  <td valign=\"top\">angle<br><sub>🆚 required</sub></td>\n  <td valign=\"top\">Entity <em>RotationAngle</em></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"speed\">\n    <img src=\"../ui/assets/icons/fixture/speed.svg\" />\n    Speed\n  </th>\n  <td valign=\"top\">speed<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Speed</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"time\">\n    <img src=\"../ui/assets/icons/fixture/speed.svg\" />\n    Time\n  </th>\n  <td valign=\"top\">time<br><sub>🌟 required</sub></td>\n  <td valign=\"top\">Entity <em>Time</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"maintenance\" rowspan=\"2\">\n    <img src=\"../ui/assets/icons/fixture/maintenance.svg\" />\n    Maintenance\n  </th>\n  <td valign=\"top\">parameter<br><sub>❔ optional</sub></td>\n  <td valign=\"top\">Entity <em>Parameter</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <td valign=\"top\">hold<br><sub>❔ optional</sub><br><sub>👣 <a href=\"#must-be-stepped\">must be stepped</a></td>\n  <td valign=\"top\">Entity <em>Time</em></td>\n  <td valign=\"top\"></td>\n</tr>\n<tr>\n  <th valign=\"top\" scope=\"row\" id=\"generic\">\n    <img src=\"../ui/assets/icons/fixture/other.svg\" />\n    Generic\n  </th>\n  <td valign=\"top\" colspan=\"3\">No type-specific properties.</td>\n</tr>\n</tbody>\n</table>\n\n### Footnotes\n\n#### Must be stepped\n\nProperties that must be stepped (they have a 👣 footsteps icon next to them) can't be appended with `Start` or `End`. E.g. only `effectName` (not `effectNameStart`/`effectNameEnd`) is allowed, while both `speed` and `speedStart`/`speedEnd` are valid.\n\n#### Property *colors*\n\n\"Individual color beams\" means that one beam is visually distinguishable from the others, i.e.:\n\n  * A Red/Green/Blue/White/Amber LED produces a single color beam, as all these color components are mixed together. For a color preset \"Red+Blue\", `colors` should be set to `[\"#ff00ff\"]`.\n  * A laser device has separate light beams that don't mix. If red and green lasers are active, `colors` should be set to `[\"#ff0000\", \"#00ff00\"]`.\n  * UV is always counted as a separate color as the ultraviolet light doesn't really mix with normal RGB colors. For a color preset \"Red+Green+UV\", `colors` should be set to `[\"#ffff00\", \"UV\"]`.\n\n\n#### Property *slotNumber*\n\nUse one-based numbering (e.g. `1` for *Open*, `2` for *Color/Gobo 1*). If the capability shows a split slot, use the value halfway between them (e.g. `2.5` for *Split Color/Gobo 1/2*). If all steps in between can be selected by the proportional capability, use `slotNumberStart` and `slotNumberEnd` (e.g. from *Color/Gobo 1* to *Color/Gobo 2*).\n\n**Note:** If there are e.g. 8 slots, and a capability allows gradually selecting anything between the last slot (*Color/Gobo 7*) and the first (*Open*) in this direction, use `\"slotNumberStart\": 8, \"slotNumberEnd\": 9`. If you chose `\"slotNumberEnd\": 1` instead, that would indicate a rotation in the other direction (i.e. over all other Gobos). Likewise, `\"slotNumberStart\": 0, \"slotNumberEnd\": 1` is also allowed.\n\n\n### How to add new capability types / type-specific properties\n\n* Update the schema (mainly `capability.json`, `definitions.json` for units / entities)\n* Update this document (both table of contents and the section itself)\n* Add new properties to the model (in `Capability.js`)\n* If it's a start/end entity, add its name to `Capability.START_END_ENTITIES`\n* Add new types to capability name generation (in `Capability.js`)\n* Add new types to channel type generation (in `CoarseChannel.js`)\n* Add a capability icon (see `ui/assets/icon` and maybe also the `app-fixture-capability-type-icon` component)\n* Update editor:\n  * Create new component in `ui/components/editor-capabilities`. Make sure it has a `defaultData` object as component data.\n  * Import the new component in the [capability component](../ui/components/editor/EditorCapabilityTypeData.vue) and register it in its `components` section.\n"
  },
  {
    "path": "docs/environment-variables.md",
    "content": "# Environment Variables\n\nWe use environment variables for configuration and storing secret credentials. They are set by [the production / test servers](ui.md#deployment) and [CI environments](testing.md) and can also be set locally; the easiest way is to edit the (gitignored) `.env` file in the project's root directory:\n\n```bash\nMY_ENV_VARIABLE=hello\n\n# Lines beginning with # are comments\nNODE_ENV=production\n```\n\nEvery script that uses environment variables must import [`lib/load-env-file.js`](../lib/load-env-file.js) as the very first statement.\n\nPlease update these docs and [`cli/debug-env-variables.js`](../cli/debug-env-variables.js) after introducing new variables.\n\n## Environment variables used by OFL\n\n| Name                              | Possible values                           | Description                        |\n|-----------------------------------|-------------------------------------------|------------------------------------|\n|`ALLOW_SEARCH_INDEXING`            | `allowed` or anything else                | If the value is not `allowed`, a `<meta>` tag is added to tell search engines not to index the page. (This is only `allowed` in the [production deployment](ui.md#deployment)) |\n|`GITHUB_USER_TOKEN`                | A 40-char [GitHub access token][gh-token] | Used to create pull request when adding fixtures and create/delete comments after running [GitHub tests](testing.md) |\n|`GITHUB_BROKEN_LINKS_ISSUE_NUMBER` | A GitHub issue number                     | Used by [tests/external-links.js](../tests/external-links.js) |\n|`NODE_ENV`                         | `production` or `development` (default)   | Introduced by Express.js, `production` enables caching, minimizing and more optimizations [improving the performance a lot][node-env-perf]. |\n|`PORT`                             | A free port number                        | On which port to start the Nuxt.js server, defaults to `3000`. |\n|`HOST`                             | A host name or IP address                 | On which host to start the Nuxt.js server, defaults to `localhost`. |\n|`WEBSITE_URL`                      | An absolute URL with a trailing slash.    | The public URL of the website. Defaults to `http://localhost:${PORT}/`. |\n|`GITHUB_PR_NUMBER`                 | A GitHub pull request number              | In a pull request, the PR number. |\n|`GITHUB_PR_HEAD_REF`               | A git ref                                 | In a pull request, the PR head ref (e.g. `feature-branch`). |\n|`GITHUB_PR_BASE_REF`               | A git ref                                 | In a pull request, the PR base ref (e.g. `master`). |\n|`GITHUB_REPOSITORY`                |                                           | [Set by GitHub Actions][gh-actions-docs] |\n|`GITHUB_RUN_ID`                    |                                           | [Set by GitHub Actions][gh-actions-docs] |\n|`GITHUB_REF`                       |                                           | [Set by GitHub Actions][gh-actions-docs] |\n\n[gh-token]: <https://github.com/settings/tokens>\n[node-env-perf]: <https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/>\n[gh-actions-docs]: <https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables>\n"
  },
  {
    "path": "docs/fixture-features.md",
    "content": "# Fixture features\n\nFixture features are specific [fixture](fixture-format.md) characteristics (like \"uses RDM\" or \"uses fine channel before coarse channel\"), especially ones that have produced or are likely to produce bugs and errors.\n\nWe use fixture features for the following purposes:\n* Generate a minimal collection of test fixtures that cover all fixture features so we can check all special cases with minimum work\n* *(planned)* The fixture editor can only edit / import fixtures that only use editor-compatible fixture features\n* *(planned)* Search for fixtures with specific fixture features (mainly for testing)\n\nFixture features are saved in the the [`lib/fixture-features/`](../lib/fixture-features/) directory as JS modules that export an array of features. It is advised to put similar features into one module. A sample module looks like this:\n\n```js\nexport default [{\n  // Optional, default is the filename (without '.js', succeeded by `-${i}` if\n  // multiple features per module are provided). Must be unique!\n  id: 'fine-channel-alias',\n\n  // Required. Used in generated table header. Try to be as short as possible! Markdown is allowed.\n  name: 'Fine channels (16bit)',\n\n  // Optional. Is used as a footnote in generated table header. Markdown is allowed.\n  description: 'Whether a channel defines exactly one fine channel alias',\n\n  /**\n   * Required. Checks if the given fixture uses this feature.\n   * @param {Fixture} fixture The Fixture instance, see fixture-model.md\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => fixture.coarseChannels.some(\n    (channel) => channel.fineChannelAliases.length === 1,\n  ),\n}];\n```\n\nTest fixtures are generated by calling `npm run build:test-fixtures` or simply `npm run build`. They are saved machine-readable as [`tests/test-fixtures.json`](../tests/test-fixtures.json) and human-readable as [`tests/test-fixtures.md`](../tests/test-fixtures.md).\n"
  },
  {
    "path": "docs/fixture-format.md",
    "content": "# JSON Fixture Format\n\nThis document gives a high-level overview of the concepts used in the JSON format of the fixture definitions collected in the *Open Fixture Library*. Those fixture definitions (also called *personalities* or *profiles*) specify information about a fixture's DMX controlment and general attributes.\n\n*Note:* The fixture format is not intended to be used directly by other software, as it may introduce breaking, not-backwards-compatible changes at any time. Instead, write a plugin to transform the data into a more stable format for your application. Internally in *OFL*, working with the [fixture model](fixture-model.md) is preferred, as it eases access to the fixture data.\n\n\n#### Table of contents\n- [Schema](#schema)\n- [Goals](#goals)\n- [Directory structure](#directory-structure)\n- [Fixture](#fixture)\n  - [Modes](#modes)\n  - [Channels](#channels)\n    - [Capabilities](#capabilities)\n    - [Fine channels](#fine-channels)\n    - [Switching channels](#switching-channels)\n  - [Matrices](#matrices)\n    - [Matrix structure](#matrix-structure)\n    - [Template channels](#template-channels)\n  - [Wheels](#wheels)\n    - [Gobo resources](#gobo-resources)\n    - [Using wheels in capabilities](#using-wheels-in-capabilities)\n  - [RDM (Remote Device Management) data](#rdm-remote-device-management-data)\n- [Fixture redirects](#fixture-redirects)\n\n\n## Schema\n\nThe [JSON Schema](https://json-schema.org/) files can be found in the [`schemas/`](../schemas/) directory. JSON Schema is a declarative way to describe allowed JSON properties and values. The [`fixtures-valid.js` test](../tests/fixtures-valid.js) automatically checks the fixtures against these schemas and additionally tests things like the correct use of channel keys etc. programmatically.\n\nThe schema files have a `version` property. Every time the schema is updated, this version needs to be incremented in all schema files using [semantic versioning](https://semver.org).\n\nGiven a version number MAJOR.MINOR.PATCH, increment the:\n1. MAJOR version when you make incompatible schema changes.  \n  i.e. old fixtures are not valid with the new schema anymore.\n2. MINOR version when you add functionality in a backwards-compatible manner.  \n  i.e. old fixtures are still valid with the new schema, new fixtures aren't valid with the old schema.\n3. PATCH version when you make backwards-compatible bug fixes.  \n  e.g. an upper bound to an integer value is added, which was likely done right in the past anyway.\n\n\n## Goals\n\nThe JSON fixture format is intended to be\n\n* readable by both humans and machines\n* easily extendable\n* as general as possible to include information for many fixture formats\n* abstract where possible, specific where needed\n\n\n## Directory structure\n\nThe manufacturer of a fixture is determined by its toplevel directory (relative to the `fixtures` directory), the fixture key is the filename without extension. Manufacturer data is stored in [`fixtures/manufacturers.json`](../fixtures/manufacturers.json).\n\n`fixtures/register.json` (which is generated by [`cli/build-register.js`](../cli/build-register.js)) is just an index to make searching specific attributes possible without having to read the whole directory structure, which makes it faster. This file is gitignored.\n\n\n## Fixture\n\nA fixture's `shortName` must be unique amongst all fixtures.\n\nThe `physical` section describes properties not directly used in the DMX protocol, but often in lighting control software to display a preview of the fixtures in action.\n\nThe `lastModifyDate` should *NOT* be updated when updating fixture data that is not related to the fixtures capabilities or attributes. This includes things such as changing an author's names, updating links, or updating the order of channel modes.\n\n\n### Modes\n\nA fixture can have multiple *modes* (also sometimes called *personalities*) like \"Basic 3-channel mode\" or \"Extended 5-channel mode\". Our modes are not allowed to have the word \"mode\" in them, as it is automatically appended at the end.\n\nA mode can contain the `physical` property to override specific physical data of the fixture. E.g. one mode could set the `power` value different than the fixture default.\n\nA mode's `shortName` must be unique amongst all modes of the respective fixture. The `shortname` should be similar to what is displayed on the device's LCD/LED displays if that information is known (e.g. from the manual). If not known, the standard `1ch` format should be followed.\n\n\n### Channels\n\nAll channels that are used in one or more modes are listed in `availableChannels`. The modes then only contain a list of the channel keys.\n\nA channel's `defaultValue` is the DMX value that this channel is set to without the user interacting (most often, this will be `0`, but e.g. for Pan and Tilt channels, other values make more sense). Likewise, `highlightValue` specifies the DMX value if a user *highlights* this channel (defaults to the maximum DMX value). This is not available in every software.\n\nIf `constant` is `true`, the channel should be set to a static value in the operating lighting program. `precedence` specifies to which value the channel should be set if there are two conflicting active cues containing this channel: *HTP* (Highest takes precedence) or *LTP* (Latest (change) takes precedence).\n\n\n#### Capabilities\n\nA channel can do different things depending on which range its DMX value currently is in. Those ranges that can be triggered manually in many programs are called capabilities. Choose a `type` to declare which property of the fixture is changed by this capability, e.g. `ShutterOpen`, `Intensity` or `Pan`. Depending on the type, there exist more properties that further describe the capability, like the pan angle, the strobe rate or the wheel slot number. Most of these are physical entities that require to be entered using specific units (like `\"10.5Hz\"` or `\"100%\"`). Some entities offer keywords to replace specific percentage values, e.g. Distance: `\"near\"` = `\"1%\"`, `\"far\"` = `\"100%\"`. See the [full list of units, entities and capability types with their properties](capability-types.md). Example:\n\n<!-- eslint-skip -->\n```js\n\"availableChannels\": {\n  \"Shutter\": {\n    \"capabilities\": [\n      {\n        \"dmxRange\": [0, 20],\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Closed\",\n        \"comment\": \"Blackout\"\n      },\n      {\n        \"dmxRange\": [21, 255],\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Open\"\n      }\n    ]\n  }\n}\n```\n\nIf a channel consists of a single 0-255 capability, one should use the `capability` property (instead of `capabilities`), which only needs a single object instead of an array of objects. The `dmxRange` is implicit in this object (see example below).\n\nCapabilities may be _steps_, which means that the whole DMX range has the same effect (e.g. \"Gobo 1\"), or _proportional_, which means that the effect is increasing / decreasing from the start to the end of the DMX range (e.g. \"Intensity 0-100%\"). A proportional capability can define a start and an end value of its type-specific properties. Example:\n\n<!-- eslint-skip -->\n```js\n\"availableChannels\": {\n  \"Pan\": {\n    \"capability\": {\n      \"type\": \"Pan\",\n      \"angleStart\": \"0deg\",\n      \"angleEnd\": \"530deg\"\n\n      // DMX value 0 -> 0°\n      // DMX value 127 -> 264°\n      // DMX value 255 -> 530°\n    }\n  }\n}\n```\n\nPlease note that some properties don't allow start/end values, for example `hold`.\n\nThe `menuClick` property defines which DMX value to use if the whole capability is selected: `start` / `center` / `end` sets the channel's DMX value to the start / center / end of the range, respectively. `hidden` hides this capability from the trigger menu. This is one of those special features that are supported only by some lighting programs.\n\n\n#### Fine channels\n\nA channel can list `fineChannelAliases` to specify which channel keys are used to describe its finer variants. This results in two or more (8 bit) channels being combined into one 16 bit (or 24 bit, ...) channel to increase the resolution of the controlled functionality.\n\nExample: Channel `Dimmer` contains `fineChannelAliases: [\"Dimmer 16-bit\", \"Dimmer 24-bit\"]`. Mode \"Normal\" uses only `Dimmer` in its channel list, mode \"Fine\" uses `Dimmer` and `Dimmer 16-bit`, mode \"Super fine\" uses all three.\n\nSee the [Generic Desk Channel fixture](../fixtures/generic/desk-channel.json) for a simple application example.\n\nDMX values (e.g. default / highlight value, capability ranges) have to be entered in the maximum resolution: If one fine channel is defined, DMX values from 0 to 65535 are possible. If a lower resolution is sufficient for entering DMX values, the channel's `dmxValueResolution` property can be set to the desired resolution (`8bit` for 0…255, `16bit` for 0…65535, etc.). That means that both of the following examples are equivalent:\n\n<!-- eslint-skip -->\n```js\n\"Iris\": {\n  \"fineChannelAliases\": [\"Iris fine\"],\n  \"defaultValue\": 33792,\n  \"capabilities\": [\n    {\n      \"dmxRange\": [0, 33791],\n      \"type\": \"Iris\",\n      \"openPercentStart\": \"100%\",\n      \"openPercentEnd\": \"4%\"\n    },\n    {\n      \"dmxRange\": [33792, 65535],\n      \"type\": \"Iris\",\n      \"openPercent\": \"4%\"\n    }\n  ]\n}\n```\n<!-- eslint-skip -->\n```js\n\"Iris\": {\n  \"fineChannelAliases\": [\"Iris fine\"],\n  \"dmxValueResolution\": \"8bit\",\n  \"defaultValue\": 132,\n  \"capabilities\": [\n    {\n      \"dmxRange\": [0, 131],\n      \"type\": \"Iris\",\n      \"openPercentStart\": \"100%\",\n      \"openPercentEnd\": \"4%\"\n    },\n    {\n      \"dmxRange\": [132, 255],\n      \"type\": \"Iris\",\n      \"openPercent\": \"4%\"\n    }\n  ]\n}\n```\n\n\n#### Switching channels\n\nA *switching channel* is a channel whose functionality depends on the value of another channel in the same mode.\n\nE.g. in a given mode, the first channel could be used to select auto-programs and channel 2 could be either \"Microphone Sensitivity\" (if channel 1 is set to *Sound control*) or \"Program Speed\" (if channel 1 is set to anything else).\n\nTo define switching channels, add a `switchChannels` object to all capabilities of the dependency channel (the \"Auto-Programs\" channel in the example above). This object defines which *switching channel alias* is set to which *available channel key* if this capability is active. The switching channel alias is then used in the mode just like a regular channel. Note that a channel which defines switching channels needs an explicit `defaultValue` to make sure that the switching channel default is also well-defined.\n\nSee the [Futurelight PRO Slim PAR-7 HCL fixture](../fixtures/futurelight/pro-slim-par-7-hcl.json) for a simple application example.\n\n\n### Matrices\n\nSome fixtures have multiple light beams: A horizontal bar of LEDs, a pixel head with a grid of lamps, a fixture consisting of inner and outer rings of LEDs that can be controlled separately, etc. See the [Eurolite LED KLS 801](../fixtures/eurolite/led-kls-801.json) and the [Pixel Bar](https://open-fixture-library.org/categories/Pixel%20Bar) and [Matrix](https://open-fixture-library.org/categories/Matrix) categories for example fixtures.\n\n#### Matrix structure\n\nThe information how these pixels are arranged is stored in the fixture's `matrix` object: Either by using the x × y × z syntax from `pixelCount` (e.g. [5, 5, 1] for a 5×5 matrix) or by naming each individual pixel in `pixelKeys`, e.g.:\n\n<!-- eslint-skip -->\n```js\n\"matrix\": {\n  \"pixelKeys\": [\n    [\n      [ null,  \"Top\",     null  ],\n      [\"Left\", \"Center\", \"Right\"],\n      [ null,  \"Bottom\",  null  ]\n    ]\n  ]\n}\n```\n\n`null` refers to a \"hole\", i.e. there's no light beam, which allows for non-cubic frames. The above example represents 5 heads arranged like a \"+\".\n\nPixels can also be grouped if a fixture allows control in different fine grades, like fourths or halves of a light bar. There are three ways to define a pixel group:\n\n* The keyword `all` indicates that all pixel keys should belong to this group. This can be useful for channels like \"Red Master\".\n* An array of pixel keys exactly describes which pixels belong to this group.\n* An object with `x`, `y`, `z` or `name` constraints. All pixels that fulfill *all* constraints belong to this group. XYZ constraints are `<=5`, `=5`, `>=5`, `3n` (divisible by 3), `3n+1` (divisible by 3 with remainder 1), `even` (≙ `2n`) and `odd` (≙ `2n+1`). Name constraints are regular expressions.\n\n<!-- eslint-skip -->\n```js\n\"matrix\": {\n  \"pixelCount\": [12, 1, 1],\n  \"pixelGroups\": {\n    \"Master\": \"all\",\n    \"1/3\": { \"x\": [\"<=4\"] },\n    \"2/3\": { \"x\": [\">=5\", \"<=8\"] },\n    \"3/3\": { \"x\": [\">=9\"] },\n    \"Outer Thirds\": [\"1\", \"2\", \"3\", \"4\", \"9\", \"10\", \"11\", \"12\"]\n  }\n}\n```\n\nSee the [TMB Solaris Flare](../fixtures/tmb/solaris-flare.json) for a rather complex example of pixel group constraints.\n\nPixel groups can also be used to better describe the pixel structure, for example to define circular rings consisting of virtual pixels, even if these pixels don't physically exist and only the whole rings can be controlled.\n\n<!-- eslint-skip -->\n```js\n\"matrix\": {\n  \"pixelKeys\": [\n    [\n      [null,  null,  \"O1\",  \"O2\",  null,  null],\n      [null,  \"O3\",  \"M1\",  \"M2\",  \"O4\",  null],\n      [\"O5\",  \"M3\",  \"I1\",  \"I2\",  \"M4\",  \"O6\"],\n      [\"O7\",  \"M5\",  \"I3\",  \"I4\",  \"M6\",  \"O8\"],\n      [null,  \"O9\",  \"M7\",  \"M8\",  \"O10\", null],\n      [null,  null,  \"O11\", \"O12\", null,  null]\n    ]\n  ],\n  \"pixelGroups\": {\n    \"Inner ring\": { \"name\": [\"^I[1-4]$\"] },\n    \"Middle ring\": { \"name\": [\"^M[1-8]$\"] },\n    \"Outer ring\":  { \"name\": [\"^O\\\\d+$\"] }\n  }\n}\n```\n\n#### Template channels\n\nTo reuse similar channels for each pixel or pixel group (like \"Red&nbsp;1\", Red&nbsp;2\", ...), add template channels: They are specified very similar to normal available channels, except that each template channel key / alias / name must contain the `$pixelKey` variable:\n\n<!-- eslint-skip -->\n```js\n\"templateChannels\": {\n  \"Red $pixelKey\": {\n    \"fineChannelAliases\": [\"Red $pixelKey fine\"],\n    \"capability\": {\n      \"type\": \"ColorIntensity\",\n      \"color\": \"Red\"\n    }\n  }\n}\n```\n\nTemplate channels can also introduce fine and switching channels. Specific resolved matrix channels can be overridden by available channels (e.g. if \"Speed&nbsp;1\" has different capabilities than \"Speed&nbsp;2\" until \"Speed&nbsp;25\"). See the [cameo Hydrabeam 300 RGBW](../fixtures/cameo/hydrabeam-300-rgbw.json) that uses these features.\n\nThen, either use the resolved channel keys directly in a mode's channel list, or use a matrix channel insert block that repeats a list of template channels for a list of pixels:\n\n<!-- eslint-skip -->\n```js\n{\n  \"name\": \"14-channel\",\n  \"shortName\": \"14ch\",\n  \"channels\": [\n    \"Master Dimmer\",\n    \"Strobe\",\n    {\n      \"insert\": \"matrixChannels\", // static value for matrix channels\n      \"repeatFor\": \"eachPixelXYZ\", // see below\n      \"channelOrder\": \"perPixel\", // see below\n      \"templateChannels\": [\n        \"Red $pixelKey\",\n        \"Green $pixelKey\",\n        \"Blue $pixelKey\"\n      ]\n    }\n  ]\n}\n```\n\n`repeatFor` defines in which order and for which pixels / pixel groups the template channels shall be repeated. Possible values are:\n\n* An array of pixel (group) keys in the proper order\n* `\"eachPixelABC\"`: Gets computed into an alphanumerically sorted list of all pixelKeys\n* `\"eachPixelXYZ\"` / `\"eachPixelZYX\"` / ...: Gets computed into a list of all pixelKeys, sorted by position, depending on the used `X`/`Y`/`Z` combination.\n  - For example, `XYZ` orders the pixels like reading a book (latin script): First left-to-right (`X`, letter by letter), then top-to-bottom (`Y`, line by line), then front-to-back (`Z`, page by page). For a 3-dimensional 2×2×2 matrix, this results in `[\"(1, 1, 1)\", \"(2, 1, 1)\", \"(1, 2, 1)\", \"(2, 2, 1)\", \"(1, 1, 2)\", \"(2, 1, 2)\", \"(1, 2, 2)\", \"(2, 2, 2)]\"`.\n* `\"eachPixelGroup\"`: Gets computed into an array of all pixel group keys, ordered by appearance in the JSON file.\n  - For the above [matrix structure](#matrix-structure) example, this results in `[\"Inner ring\", \"Middle ring\", \"Outer ring\"]`.\n\n`channelOrder` defines how the channels are ordered. Possible values are:\n\n* `\"perPixel\"`: For the above [matrix structure](#matrix-structure) example, this results in\n  ```json\n  [\n    \"Red Inner ring\", \"Green Inner ring\", \"Blue Inner ring\",\n    \"Red Middle ring\", \"Green Middle ring\", \"Blue Middle ring\",\n    \"Red Outer ring\", \"Green Outer ring\", \"Blue Outer ring\"\n  ]\n  ```\n* `\"perChannel\"`: For the above [matrix structure](#matrix-structure) example, this results in\n  ```json\n  [\n    \"Red Inner ring\", \"Red Middle ring\", \"Red Outer ring\",\n    \"Green Inner ring\", \"Green Middle ring\", \"Green Outer ring\",\n    \"Blue Inner ring\", \"Blue Middle ring\", \"Blue Outer ring\"\n  ]\n  ```\n\n### Wheels\n\nFixtures (usually moving heads) can have internal wheels, where you can select the active slot via DMX. In our fixture format, wheels are defined in the fixture's `wheels` object, where the key defines the wheel's name.\n\nThe slots in a wheel have types, similar to [capability types](capability-types.md). Depending on the type, different properties can be set on the slot.\n\n* `Open` / `Closed`\n* `Color`\n  - `name` (string)\n  - `colors` (array of hex strings)\n  - `colorTemperature` ([Entity](capability-types.md#possible-entities-and-keywords) *ColorTemperature*)\n* `Gobo`\n  - `resource` (resource reference string, see below)\n  - `name` (string)\n* `Prism`\n  - `name` (string)\n  - `facets` (integer)\n* `Iris`\n  - `openPercent` ([Entity](capability-types.md#possible-entities-and-keywords) *IrisPercent*)\n* `Frost`\n  - `frostIntensity` ([Entity](capability-types.md#possible-entities-and-keywords) *Percent*)\n* `AnimationGoboStart`\n  - `name` (string)\n* `AnimationGoboEnd`\n\nAnimation Gobo slots are wider than normal gobos (sometimes they fill the whole wheel); rotating the wheel over these slots creates an animation. To model the wider slots, an `AnimationGoboEnd` slot must be used directly after an `AnimationGoboStart` slot.\n\n#### Gobo resources\n\nGobos are referenced with a resource reference in the form `gobos/<gobo key>`.\n\nGobo resources are stored in the [`resources/gobos/`](../resources/gobos/) directory. Each one consists of a JSON file (`<gobo key>.json`) describing the gobo (with name, keywords, and a source where the gobo image was extracted from) and the gobo image itself (`<gobo key>.svg` or `<gobo key>.png`).\n\nIn the [`resources/gobos/aliases/`](../resources/gobos/aliases/) directory, sets of aliases can be defined as separate JSON files in which aliases are mapped to gobo keys. This is useful for plugins (e.g. the QLC+ import plugin knows which OFL gobo key to use when QLC+ gobo `Others/0001.svg` is referenced in a fixture). It also enables referencing gobos in fixture files with an alias like `gobos/aliases/<alias file>/<alias key>` (e.g. a Robe fixture could reference `gobos/aliases/robe/15020246-rafia`) to make validating the gobo information easier with a manual where product numbers are specified.\n\n#### Using wheels in capabilities\n\nIn wheel-related capabilities, the `wheel` property references the wheel by its name. If the `wheel` property is not set, the channel name is used as wheel name.\n\n`WheelSlot` capabilities select a slot from the wheel. If the capability selects the place in between two slots, the `slotNumber` property can be set to a fractional value (or be proportional as `slotNumberStart` / `slotNumberEnd`). See also [footnote *slotNumber* in the capability types documentation](capability-types.md#property-slotnumber).\n\n`WheelShake` capabilities set the shaking (i.e. continuously rotating back and forth) of the whole wheel around the currently selected slot. A slot can also be activated directly by setting the `slotNumber` property like in `WheelSlot` capabilities.  \nBy setting the property `isShaking` to `slot`, one can specify that only the currently selected slot rotates back and forth around its center (sometimes called *Gobo bounce effect*) instead of the whole wheel.\n\n`WheelSlotRotation` capabilities control the rotation of the currently selected slot (i.e. Gobo, Prism, etc.). A slot can also be activated directly by setting the `slotNumber` property like in `WheelSlot` capabilities.\n\n`WheelRotation` capabilities rotate the whole wheel, i.e. over all slots.\n\n\n### RDM (Remote Device Management) data\n\nWe link to [Open Lighting's RDM database](http://rdm.openlighting.org) if possible. Thus, we need to specify the RDM manufacturer ID per manufacturer and the RDM model ID per fixture. Additionally, each mode is mapped to the respective RDM personality via the `rdmPersonalityIndex` property. To ensure compatibility, we also track, for which RDM fixture software (firmware) version the mode indices are specified.\n\nIf RDM manufacturer and model ID are known, we open the respective fixture page when going to `/rdm` (handled in [`ui/pages/rdm.vue`](../ui/pages/rdm.vue)).\n\n\n## Fixture redirects\n\nFixtures may be renamed by their manufacturers. If we would just update the fixture definition, links to its old fixture page would now lead to a *404 Not found* error. Instead, we add a fixture redirect JSON file (see [its schema](../schemas/fixture-redirect.json)) with the old manufacturer / fixture key, pointing to the updated fixture definition. See [Minuit Une M-Carré](../fixtures/minuit-une/m-carre.json) (and its [fixture page on OFL](https://open-fixture-library.org/minuit-une/m-carre)) as an example.\n\nAnother use case for redirects are fixtures that are sold under different brands, but which are technically the same. We add them to the library only once and let redirects with other names point to it.\n"
  },
  {
    "path": "docs/fixture-model.md",
    "content": "# Fixture model\n\nInstead of parsing [fixtures' JSON data](fixture-format.md) directly, it is recommended to use the model. We developed it to ease handling complicated fixture features like fine channels or switching channels.\n\nAll model functions and classes are documented with [JSDoc](https://jsdoc.app/). Those annotations are converted to Markdown with [jsdoc2md](https://github.com/jsdoc2md/jsdoc-to-markdown) to obtain an [API reference](model-api.md).\n\nThe model uses [ES2015 classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) in [ES2015 modules](https://nodejs.org/api/esm.html) to represent the fixtures. E.g., `fixtureFromRepository('cameo', 'nanospot-120')` returns a [`Fixture`](model-api.md#Fixture) object, instantiated with the specified fixture's data. These objects have several convenient properties that allow easy usage of the fixture data in [plugins](plugins.md), [UI](ui.md) and more.\n\nAll model classes are located in the [`lib/model/`](../lib/model) directory. When using the model, it usually suffices to import the `fixtureFromRepository` function from `model.js` which returns a `Fixture` instance:\n\n```js\nimport { fixtureFromRepository } from './lib/model.js';\n\nconst myFixture = await fixtureFromRepository('cameo', 'nanospot-120'); // instanceof Fixture\n\nconst physicalData = myFixture.physical; // instanceof Physical\nconst panFine = myFixture.getChannelByKey('Pan fine'); // instanceof FineChannel\n\nif (panFine.coarseChannel.hasHighlightValue) {\n  console.log(`Highlight at ${panFine.coarseChannel.highlightValue}`);\n}\n```\n\nModel properties are always implemented using getters and setters. To store data, we use backing fields (an internal property prefixed with underscore, e.g. `_jsonObject`) to hold the data. The backing field should never be accessed directly, but only through its getter and setter functions (without underscore).\n\nAvoid returning `undefined` by returning smart default values if necessary. If the default value is not `null`, also provide a `hasXY` boolean getter function. Properties that need further computation or create other objects should be cached using the [lazy-loading property pattern](https://humanwhocodes.com/blog/2021/04/lazy-loading-property-pattern-javascript/) using the [`cacheResult` function](../lib/cache-result.js).\n\n```js\nimport cacheResult from '../lib/cache-result.js';\n\nexport default class Fixture {\n  constructor(jsonObject) {\n    this._jsonObject = jsonObject;\n  }\n\n  // returns backing field to avoid accessing _jsonObject from outside\n  get jsonObject() {\n    return this._jsonObject;\n  }\n\n  // required, no default needed\n  get name() {\n    return this._jsonObject.name;\n  }\n\n  // defaults to the name\n  get shortName() {\n    return this._jsonObject.shortName || this._jsonObject.name;\n  }\n\n  get hasShortName() {\n    return 'shortName' in this._jsonObject;\n  }\n\n  // avoid creating a new Meta object for each property access by caching it\n  get meta() {\n    return cacheResult(this, 'meta', new Meta(this._jsonObject.meta));\n  }\n\n  // defaults to null as there is no meaningful other default\n  get rdm() {\n    return this._jsonObject.rdm || null;\n  }\n\n  // ...\n}\n```\n\n## Resource references\n\nResources (e.g. gobo images) are embedded by the model into the fixture JSON, i.e. instead of returning a string, `WheelSlot.resource` will return the resource object. The relevant code is in the `embedResourcesIntoFixtureJson` function in [`lib/model.js](../lib/model.js).\n\nThus, all information needed for the fixure is still included in the fixture JSON.\n"
  },
  {
    "path": "docs/model-api.md",
    "content": "## Classes\n\n<dl>\n<dt><a href=\"#AbstractChannel\">AbstractChannel</a></dt>\n<dd><p>Base class for channels.</p>\n</dd>\n<dt><a href=\"#Capability\">Capability</a></dt>\n<dd><p>A capability represents a range of a channel.</p>\n</dd>\n<dt><a href=\"#CoarseChannel\">CoarseChannel</a> ⇐ <code><a href=\"#AbstractChannel\">AbstractChannel</a></code></dt>\n<dd><p>A single DMX channel, either created as availableChannel or resolved templateChannel.\nOnly the MSB (most significant byte) channel if it&#39;s a multi-byte channel.</p>\n</dd>\n<dt><a href=\"#Entity\">Entity</a></dt>\n<dd><p>A physical entity with numerical value and unit information.</p>\n</dd>\n<dt><a href=\"#FineChannel\">FineChannel</a> ⇐ <code><a href=\"#AbstractChannel\">AbstractChannel</a></code></dt>\n<dd><p>Represents a finer channel of a 16+ bit channel.\nAlso called LSB (least significant byte) channel.</p>\n</dd>\n<dt><a href=\"#Fixture\">Fixture</a></dt>\n<dd><p>A physical DMX device.</p>\n</dd>\n<dt><a href=\"#Manufacturer\">Manufacturer</a></dt>\n<dd><p>A company or brand that produces fixtures. A fixture is associated to exactly one manufacturer.</p>\n</dd>\n<dt><a href=\"#Matrix\">Matrix</a></dt>\n<dd><p>Contains information of how the pixels in a 1-, 2- or 3-dimensional space are arranged and named.</p>\n</dd>\n<dt><a href=\"#Meta\">Meta</a></dt>\n<dd><p>Information about a fixture&#39;s author and history.</p>\n</dd>\n<dt><a href=\"#Mode\">Mode</a></dt>\n<dd><p>A fixture&#39;s configuration that enables a fixed set of channels and channel order.</p>\n</dd>\n<dt><a href=\"#NullChannel\">NullChannel</a> ⇐ <code><a href=\"#CoarseChannel\">CoarseChannel</a></code></dt>\n<dd><p>Dummy channel used to represent <code>null</code> in a mode&#39;s channel list.</p>\n</dd>\n<dt><a href=\"#Physical\">Physical</a></dt>\n<dd><p>A fixture&#39;s technical data, belonging to the hardware and not the DMX protocol.</p>\n</dd>\n<dt><a href=\"#Range\">Range</a></dt>\n<dd><p>Represents a range from one integer to a higher or equal integer. Primarily used for DMX ranges of capabilities.</p>\n</dd>\n<dt><a href=\"#Resource\">Resource</a></dt>\n<dd><p>Information about a resource.</p>\n</dd>\n<dt><a href=\"#SwitchingChannel\">SwitchingChannel</a> ⇐ <code><a href=\"#AbstractChannel\">AbstractChannel</a></code></dt>\n<dd><p>Represents a channel that switches its behavior depending on trigger channel&#39;s value.\nThe different behaviors are implemented as different <a href=\"#CoarseChannel\">CoarseChannel</a>s or <a href=\"#FineChannel\">FineChannel</a>s.</p>\n</dd>\n<dt><a href=\"#TemplateChannel\">TemplateChannel</a></dt>\n<dd><p>Represents a blueprint channel of which several similar channels can be generated.\nCurrently used to create matrix channels.</p>\n</dd>\n<dt><a href=\"#Wheel\">Wheel</a></dt>\n<dd><p>Information about a fixture&#39;s wheel.</p>\n</dd>\n<dt><a href=\"#WheelSlot\">WheelSlot</a></dt>\n<dd><p>Information about a single wheel slot (or a split slot).</p>\n</dd>\n</dl>\n\n## Typedefs\n\n<dl>\n<dt><a href=\"#Resolution\">Resolution</a> : <code>number</code></dt>\n<dd><p>1 for 8bit, 2 for 16bit, ...</p>\n</dd>\n<dt><a href=\"#TriggerCapability\">TriggerCapability</a> : <code>object</code></dt>\n<dd></dd>\n<dt><a href=\"#SwitchingChannelBehavior\">SwitchingChannelBehavior</a> : <code>&#x27;keyOnly&#x27;</code> | <code>&#x27;defaultOnly&#x27;</code> | <code>&#x27;switchedOnly&#x27;</code> | <code>&#x27;all&#x27;</code></dt>\n<dd></dd>\n</dl>\n\n<a name=\"AbstractChannel\"></a>\n\n## *AbstractChannel*\nBase class for channels.\n\n**Kind**: global abstract class  \n\n* *[AbstractChannel](#AbstractChannel)*\n    * *[new AbstractChannel(key)](#new_AbstractChannel_new)*\n    * **[.fixture](#AbstractChannel+fixture) ⇒ [<code>Fixture</code>](#Fixture)**\n    * *[.key](#AbstractChannel+key) ⇒ <code>string</code>*\n    * *[.name](#AbstractChannel+name) ⇒ <code>string</code>*\n    * *[.uniqueName](#AbstractChannel+uniqueName) ⇒ <code>string</code>*\n    * *[.pixelKey](#AbstractChannel+pixelKey) ⇒ <code>string</code> \\| <code>null</code>*\n    * *[.pixelKey](#AbstractChannel+pixelKey)*\n\n<a name=\"new_AbstractChannel_new\"></a>\n\n### *new AbstractChannel(key)*\nCreate a new AbstractChannel instance. Call this from child classes as `super(key)`.\n\n**Throws**:\n\n- <code>TypeError</code> If the AbstractChannel is instantiated directly.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| key | <code>string</code> | The channel's identifier, must be unique in the fixture. |\n\n<a name=\"AbstractChannel+fixture\"></a>\n\n### **abstractChannel.fixture ⇒ [<code>Fixture</code>](#Fixture)**\n**Kind**: instance abstract property of [<code>AbstractChannel</code>](#AbstractChannel)  \n**Returns**: [<code>Fixture</code>](#Fixture) - The fixture instance this channel is associated to.  \n**Throws**:\n\n- <code>TypeError</code> If this property is not overridden in child classes.\n\n<a name=\"AbstractChannel+key\"></a>\n\n### *abstractChannel.key ⇒ <code>string</code>*\n**Kind**: instance property of [<code>AbstractChannel</code>](#AbstractChannel)  \n**Returns**: <code>string</code> - The channel key.  \n<a name=\"AbstractChannel+name\"></a>\n\n### *abstractChannel.name ⇒ <code>string</code>*\nOverride this method for more sensible implementation.\n\n**Kind**: instance property of [<code>AbstractChannel</code>](#AbstractChannel)  \n**Returns**: <code>string</code> - The channel key (as name).  \n<a name=\"AbstractChannel+uniqueName\"></a>\n\n### *abstractChannel.uniqueName ⇒ <code>string</code>*\n**Kind**: instance property of [<code>AbstractChannel</code>](#AbstractChannel)  \n**Returns**: <code>string</code> - Unique version of this channel's name.  \n**See**: [uniqueChannelNames](#Fixture+uniqueChannelNames)  \n<a name=\"AbstractChannel+pixelKey\"></a>\n\n### *abstractChannel.pixelKey ⇒ <code>string</code> \\| <code>null</code>*\n**Kind**: instance property of [<code>AbstractChannel</code>](#AbstractChannel)  \n**Returns**: <code>string</code> \\| <code>null</code> - The key of the pixel (group) that this channel is associated to. Defaults to null.  \n<a name=\"AbstractChannel+pixelKey\"></a>\n\n### *abstractChannel.pixelKey*\n**Kind**: instance property of [<code>AbstractChannel</code>](#AbstractChannel)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| pixelKey | <code>string</code> \\| <code>null</code> | The key of the pixel (group) that this channel is associated to. Set to null to dereference a channel from a pixel (group). |\n\n<a name=\"Capability\"></a>\n\n## Capability\nA capability represents a range of a channel.\n\n**Kind**: global class  \n\n* [Capability](#Capability)\n    * [new Capability(jsonObject, resolution, channel)](#new_Capability_new)\n    * _instance_\n        * [.jsonObject](#Capability+jsonObject) ⇒ <code>object</code>\n        * [.dmxRange](#Capability+dmxRange) ⇒ [<code>Range</code>](#Range)\n        * [.rawDmxRange](#Capability+rawDmxRange) ⇒ [<code>Range</code>](#Range)\n        * [.type](#Capability+type) ⇒ <code>string</code>\n        * [.name](#Capability+name) ⇒ <code>string</code>\n        * [.hasComment](#Capability+hasComment) ⇒ <code>boolean</code>\n        * [.comment](#Capability+comment) ⇒ <code>string</code>\n        * [.isStep](#Capability+isStep) ⇒ <code>boolean</code>\n        * [.isInverted](#Capability+isInverted) ⇒ <code>boolean</code>\n        * [.usedStartEndEntities](#Capability+usedStartEndEntities) ⇒ <code>Array.&lt;string&gt;</code>\n        * [.helpWanted](#Capability+helpWanted) ⇒ <code>string</code> \\| <code>null</code>\n        * [.menuClick](#Capability+menuClick) ⇒ <code>&#x27;start&#x27;</code> \\| <code>&#x27;center&#x27;</code> \\| <code>&#x27;end&#x27;</code> \\| <code>&#x27;hidden&#x27;</code>\n        * [.menuClickDmxValue](#Capability+menuClickDmxValue) ⇒ <code>number</code>\n        * [.switchChannels](#Capability+switchChannels) ⇒ <code>Record.&lt;string, string&gt;</code>\n        * [.shutterEffect](#Capability+shutterEffect) ⇒ <code>string</code> \\| <code>null</code>\n        * [.color](#Capability+color) ⇒ <code>&#x27;Red&#x27;</code> \\| <code>&#x27;Green&#x27;</code> \\| <code>&#x27;Blue&#x27;</code> \\| <code>&#x27;Cyan&#x27;</code> \\| <code>&#x27;Magenta&#x27;</code> \\| <code>&#x27;Yellow&#x27;</code> \\| <code>&#x27;Amber&#x27;</code> \\| <code>&#x27;White&#x27;</code> \\| <code>&#x27;Warm White&#x27;</code> \\| <code>&#x27;Cold White&#x27;</code> \\| <code>&#x27;UV&#x27;</code> \\| <code>&#x27;Lime&#x27;</code> \\| <code>&#x27;Indigo&#x27;</code> \\| <code>null</code>\n        * [.colors](#Capability+colors) ⇒ <code>object</code> \\| <code>null</code>\n        * [.wheels](#Capability+wheels) ⇒ [<code>Array.&lt;Wheel&gt;</code>](#Wheel)\n        * [.isShaking](#Capability+isShaking) ⇒ <code>&#x27;slot&#x27;</code> \\| <code>&#x27;wheel&#x27;</code>\n        * [.effectName](#Capability+effectName) ⇒ <code>string</code> \\| <code>null</code>\n        * [.effectPreset](#Capability+effectPreset) ⇒ <code>string</code> \\| <code>null</code>\n        * [.isSoundControlled](#Capability+isSoundControlled) ⇒ <code>boolean</code>\n        * [.randomTiming](#Capability+randomTiming) ⇒ <code>boolean</code>\n        * [.blade](#Capability+blade) ⇒ <code>&#x27;Top&#x27;</code> \\| <code>&#x27;Right&#x27;</code> \\| <code>&#x27;Bottom&#x27;</code> \\| <code>&#x27;Left&#x27;</code> \\| <code>number</code> \\| <code>null</code>\n        * [.fogType](#Capability+fogType) ⇒ <code>&#x27;Fog&#x27;</code> \\| <code>&#x27;Haze&#x27;</code> \\| <code>null</code>\n        * [.hold](#Capability+hold) ⇒ [<code>Entity</code>](#Entity) \\| <code>null</code>\n        * [.speed](#Capability+speed) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.duration](#Capability+duration) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.time](#Capability+time) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.brightness](#Capability+brightness) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.slotNumber](#Capability+slotNumber) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.wheelSlot](#Capability+wheelSlot) ⇒ [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot) \\| <code>null</code>\n        * [.angle](#Capability+angle) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.horizontalAngle](#Capability+horizontalAngle) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.verticalAngle](#Capability+verticalAngle) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.colorTemperature](#Capability+colorTemperature) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.soundSensitivity](#Capability+soundSensitivity) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.shakeAngle](#Capability+shakeAngle) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.shakeSpeed](#Capability+shakeSpeed) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.distance](#Capability+distance) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.openPercent](#Capability+openPercent) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.frostIntensity](#Capability+frostIntensity) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.insertion](#Capability+insertion) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.fogOutput](#Capability+fogOutput) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.parameter](#Capability+parameter) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n        * [.getDmxRangeWithResolution(desiredResolution)](#Capability+getDmxRangeWithResolution) ⇒ [<code>Range</code>](#Range)\n        * [.canCrossfadeTo(nextCapability)](#Capability+canCrossfadeTo) ⇒ <code>boolean</code>\n        * [.getMenuClickDmxValueWithResolution(desiredResolution)](#Capability+getMenuClickDmxValueWithResolution) ⇒ <code>number</code>\n        * [.isSlotType(slotType)](#Capability+isSlotType) ⇒ <code>boolean</code>\n        * [._getStartEndArray(property)](#Capability+_getStartEndArray) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> ℗\n    * _static_\n        * [.START_END_ENTITIES](#Capability.START_END_ENTITIES) ⇒ <code>Array.&lt;string&gt;</code>\n\n<a name=\"new_Capability_new\"></a>\n\n### new Capability(jsonObject, resolution, channel)\nCreate a new Capability instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| jsonObject | <code>object</code> | The capability data from the channel's JSON. |\n| resolution | [<code>Resolution</code>](#Resolution) | How fine this capability is declared. |\n| channel | [<code>CoarseChannel</code>](#CoarseChannel) | The channel instance this channel is associated to. |\n\n<a name=\"Capability+jsonObject\"></a>\n\n### capability.jsonObject ⇒ <code>object</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>object</code> - The capability data from the channel's JSON.  \n<a name=\"Capability+dmxRange\"></a>\n\n### capability.dmxRange ⇒ [<code>Range</code>](#Range)\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Range</code>](#Range) - The capability's DMX bounds in the channel's highest resolution.  \n<a name=\"Capability+rawDmxRange\"></a>\n\n### capability.rawDmxRange ⇒ [<code>Range</code>](#Range)\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Range</code>](#Range) - The capability's DMX bounds from the JSON data.  \n<a name=\"Capability+type\"></a>\n\n### capability.type ⇒ <code>string</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>string</code> - Describes which feature is controlled by this capability.  \n<a name=\"Capability+name\"></a>\n\n### capability.name ⇒ <code>string</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>string</code> - Short one-line description of the capability, generated from the capability's type and type-specific properties.  \n<a name=\"Capability+hasComment\"></a>\n\n### capability.hasComment ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>boolean</code> - Whether this capability has a comment set.  \n<a name=\"Capability+comment\"></a>\n\n### capability.comment ⇒ <code>string</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>string</code> - Short additional information on this capability  \n<a name=\"Capability+isStep\"></a>\n\n### capability.isStep ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>boolean</code> - Whether this capability has the same effect from the start to the end.  \n<a name=\"Capability+isInverted\"></a>\n\n### capability.isInverted ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>boolean</code> - Whether this capability ranges from a high to a low value (e.g. speed fast…slow).  \n<a name=\"Capability+usedStartEndEntities\"></a>\n\n### capability.usedStartEndEntities ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Names of non-null properties with (maybe equal) start/end value.  \n<a name=\"Capability+helpWanted\"></a>\n\n### capability.helpWanted ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>string</code> \\| <code>null</code> - A string describing the help that is needed for this capability, or null if no help is needed.  \n<a name=\"Capability+menuClick\"></a>\n\n### capability.menuClick ⇒ <code>&#x27;start&#x27;</code> \\| <code>&#x27;center&#x27;</code> \\| <code>&#x27;end&#x27;</code> \\| <code>&#x27;hidden&#x27;</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>&#x27;start&#x27;</code> \\| <code>&#x27;center&#x27;</code> \\| <code>&#x27;end&#x27;</code> \\| <code>&#x27;hidden&#x27;</code> - The method which DMX value to set when this capability is chosen in a lighting software's auto menu.  \n<a name=\"Capability+menuClickDmxValue\"></a>\n\n### capability.menuClickDmxValue ⇒ <code>number</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>number</code> - The DMX value to set when this capability is chosen in a lighting software's auto menu.  \n<a name=\"Capability+switchChannels\"></a>\n\n### capability.switchChannels ⇒ <code>Record.&lt;string, string&gt;</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>Record.&lt;string, string&gt;</code> - Switching channel aliases mapped to the channel key to which the switching channel should be set to when this capability is activated.  \n<a name=\"Capability+shutterEffect\"></a>\n\n### capability.shutterEffect ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>string</code> \\| <code>null</code> - Behavior for the shutter, for example 'Closed', 'Strobe' or 'Pulse'. Defaults to null.  \n<a name=\"Capability+color\"></a>\n\n### capability.color ⇒ <code>&#x27;Red&#x27;</code> \\| <code>&#x27;Green&#x27;</code> \\| <code>&#x27;Blue&#x27;</code> \\| <code>&#x27;Cyan&#x27;</code> \\| <code>&#x27;Magenta&#x27;</code> \\| <code>&#x27;Yellow&#x27;</code> \\| <code>&#x27;Amber&#x27;</code> \\| <code>&#x27;White&#x27;</code> \\| <code>&#x27;Warm White&#x27;</code> \\| <code>&#x27;Cold White&#x27;</code> \\| <code>&#x27;UV&#x27;</code> \\| <code>&#x27;Lime&#x27;</code> \\| <code>&#x27;Indigo&#x27;</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>&#x27;Red&#x27;</code> \\| <code>&#x27;Green&#x27;</code> \\| <code>&#x27;Blue&#x27;</code> \\| <code>&#x27;Cyan&#x27;</code> \\| <code>&#x27;Magenta&#x27;</code> \\| <code>&#x27;Yellow&#x27;</code> \\| <code>&#x27;Amber&#x27;</code> \\| <code>&#x27;White&#x27;</code> \\| <code>&#x27;Warm White&#x27;</code> \\| <code>&#x27;Cold White&#x27;</code> \\| <code>&#x27;UV&#x27;</code> \\| <code>&#x27;Lime&#x27;</code> \\| <code>&#x27;Indigo&#x27;</code> \\| <code>null</code> - The color of the lamp that is controlled by this ColorIntensity capability. Defaults to null.  \n<a name=\"Capability+colors\"></a>\n\n### capability.colors ⇒ <code>object</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>object</code> \\| <code>null</code> - The color hex codes for each visually distinguishable light beam. Defaults to null.  \n<a name=\"Capability+wheels\"></a>\n\n### capability.wheels ⇒ [<code>Array.&lt;Wheel&gt;</code>](#Wheel)\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Wheel&gt;</code>](#Wheel) - The wheels this capability refers to. The array has one or more elements in wheel-related capabilities, zero otherwise.  \n<a name=\"Capability+isShaking\"></a>\n\n### capability.isShaking ⇒ <code>&#x27;slot&#x27;</code> \\| <code>&#x27;wheel&#x27;</code>\nUse only in `WheelShake` capabilities!\n\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>&#x27;slot&#x27;</code> \\| <code>&#x27;wheel&#x27;</code> - The fixture component that is shaking.  \n<a name=\"Capability+effectName\"></a>\n\n### capability.effectName ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>string</code> \\| <code>null</code> - Describes the effect that this capability activates. May be a pretty name for an effect preset. Defaults to null.  \n<a name=\"Capability+effectPreset\"></a>\n\n### capability.effectPreset ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>string</code> \\| <code>null</code> - Describes the effect that this capability activates by using a predefined, standard name. Defaults to null.  \n<a name=\"Capability+isSoundControlled\"></a>\n\n### capability.isSoundControlled ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>boolean</code> - Whether this effect is controlled by sound perceived by a microphone. Defaults to false.  \n<a name=\"Capability+randomTiming\"></a>\n\n### capability.randomTiming ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>boolean</code> - Whether this capability's speed / duration varies by a random offset. Defaults to false.  \n<a name=\"Capability+blade\"></a>\n\n### capability.blade ⇒ <code>&#x27;Top&#x27;</code> \\| <code>&#x27;Right&#x27;</code> \\| <code>&#x27;Bottom&#x27;</code> \\| <code>&#x27;Left&#x27;</code> \\| <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>&#x27;Top&#x27;</code> \\| <code>&#x27;Right&#x27;</code> \\| <code>&#x27;Bottom&#x27;</code> \\| <code>&#x27;Left&#x27;</code> \\| <code>number</code> \\| <code>null</code> - At which position the blade is attached. Defaults to null.  \n<a name=\"Capability+fogType\"></a>\n\n### capability.fogType ⇒ <code>&#x27;Fog&#x27;</code> \\| <code>&#x27;Haze&#x27;</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>&#x27;Fog&#x27;</code> \\| <code>&#x27;Haze&#x27;</code> \\| <code>null</code> - The kind of fog that should be emitted. Defaults to null.  \n<a name=\"Capability+hold\"></a>\n\n### capability.hold ⇒ [<code>Entity</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Entity</code>](#Entity) \\| <code>null</code> - How long this capability should be selected to take effect. Defaults to null.  \n<a name=\"Capability+speed\"></a>\n\n### capability.speed ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end speed values. Defaults to null.  \n<a name=\"Capability+duration\"></a>\n\n### capability.duration ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end duration values. Defaults to null.  \n<a name=\"Capability+time\"></a>\n\n### capability.time ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end time values. Defaults to null.  \n<a name=\"Capability+brightness\"></a>\n\n### capability.brightness ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end brightness values. Defaults to null.  \n<a name=\"Capability+slotNumber\"></a>\n\n### capability.slotNumber ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end slot numbers. Defaults to null.  \n<a name=\"Capability+wheelSlot\"></a>\n\n### capability.wheelSlot ⇒ [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot) \\| <code>null</code> - Start and end wheel slot objects this capability is referencing. Defaults to null.  \n<a name=\"Capability+angle\"></a>\n\n### capability.angle ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end angle values. Defaults to null.  \n<a name=\"Capability+horizontalAngle\"></a>\n\n### capability.horizontalAngle ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end horizontal angle values. Defaults to null.  \n<a name=\"Capability+verticalAngle\"></a>\n\n### capability.verticalAngle ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end vertical angle values. Defaults to null.  \n<a name=\"Capability+colorTemperature\"></a>\n\n### capability.colorTemperature ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end colorTemperature values. Defaults to null.  \n<a name=\"Capability+soundSensitivity\"></a>\n\n### capability.soundSensitivity ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end sound sensitivity values. Defaults to null.  \n<a name=\"Capability+shakeAngle\"></a>\n\n### capability.shakeAngle ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end shake angle values. Defaults to null.  \n<a name=\"Capability+shakeSpeed\"></a>\n\n### capability.shakeSpeed ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end shake speed values. Defaults to null.  \n<a name=\"Capability+distance\"></a>\n\n### capability.distance ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end distance values. Defaults to null.  \n<a name=\"Capability+openPercent\"></a>\n\n### capability.openPercent ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end openPercent values. Defaults to null.  \n<a name=\"Capability+frostIntensity\"></a>\n\n### capability.frostIntensity ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end frostIntensity values. Defaults to null.  \n<a name=\"Capability+insertion\"></a>\n\n### capability.insertion ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end insertion values. Defaults to null.  \n<a name=\"Capability+fogOutput\"></a>\n\n### capability.fogOutput ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end fogOutput values. Defaults to null.  \n<a name=\"Capability+parameter\"></a>\n\n### capability.parameter ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end parameter values. Defaults to null.  \n<a name=\"Capability+getDmxRangeWithResolution\"></a>\n\n### capability.getDmxRangeWithResolution(desiredResolution) ⇒ [<code>Range</code>](#Range)\n**Kind**: instance method of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Range</code>](#Range) - The capability's DMX bounds scaled (down) to the given resolution.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| desiredResolution | <code>number</code> | The grade of resolution the dmxRange should be scaled to. |\n\n<a name=\"Capability+canCrossfadeTo\"></a>\n\n### capability.canCrossfadeTo(nextCapability) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>Capability</code>](#Capability)  \n**Returns**: <code>boolean</code> - Whether this capability's end value equals the given capability's start value, i. e. one can fade from this capability to the given one.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| nextCapability | [<code>Capability</code>](#Capability) | The next capability after this one. |\n\n<a name=\"Capability+getMenuClickDmxValueWithResolution\"></a>\n\n### capability.getMenuClickDmxValueWithResolution(desiredResolution) ⇒ <code>number</code>\n**Kind**: instance method of [<code>Capability</code>](#Capability)  \n**Returns**: <code>number</code> - The DMX value (scaled to the given resolution) to set when this capability is chosen in a lighting software's auto menu, or -1 if the capability should be hidden in the auto menu.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| desiredResolution | <code>number</code> | The grade of resolution the dmxRange should be scaled to. |\n\n<a name=\"Capability+isSlotType\"></a>\n\n### capability.isSlotType(slotType) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>Capability</code>](#Capability)  \n**Returns**: <code>boolean</code> - True if the capability references a slot (or range of slots) of the given type, false otherwise.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| slotType | <code>string</code> \\| <code>RegExp</code> | The type of the slot to check. Can be a regular expression to be checked against the type. |\n\n<a name=\"Capability+_getStartEndArray\"></a>\n\n### capability.\\_getStartEndArray(property) ⇒ [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> ℗\nParses a property that has start and end variants by generating an array with start and end value.\n\n**Kind**: instance method of [<code>Capability</code>](#Capability)  \n**Returns**: [<code>Array.&lt;Entity&gt;</code>](#Entity) \\| <code>null</code> - Start and end value of the property (may be equal), parsed to Entity instances. null if it isn't defined in JSON.  \n**Access**: private  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| property | <code>string</code> | The base property name. 'Start' and 'End' will be appended to get the start/end variants. |\n\n<a name=\"Capability.START_END_ENTITIES\"></a>\n\n### Capability.START\\_END\\_ENTITIES ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: static property of [<code>Capability</code>](#Capability)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Type-specific properties that may have a start and an end value.  \n<a name=\"CoarseChannel\"></a>\n\n## CoarseChannel ⇐ [<code>AbstractChannel</code>](#AbstractChannel)\nA single DMX channel, either created as availableChannel or resolved templateChannel.\nOnly the MSB (most significant byte) channel if it's a multi-byte channel.\n\n**Kind**: global class  \n**Extends**: [<code>AbstractChannel</code>](#AbstractChannel)  \n\n* [CoarseChannel](#CoarseChannel) ⇐ [<code>AbstractChannel</code>](#AbstractChannel)\n    * [new CoarseChannel(key, jsonObject, fixture)](#new_CoarseChannel_new)\n    * _instance_\n        * [.jsonObject](#CoarseChannel+jsonObject) ⇒ <code>object</code>\n        * [.fixture](#CoarseChannel+fixture) ⇒ [<code>Fixture</code>](#Fixture)\n        * [.name](#CoarseChannel+name) ⇒ <code>string</code>\n        * [.type](#CoarseChannel+type) ⇒ <code>string</code>\n        * [.color](#CoarseChannel+color) ⇒ <code>string</code> \\| <code>null</code>\n        * [.fineChannelAliases](#CoarseChannel+fineChannelAliases) ⇒ <code>Array.&lt;string&gt;</code>\n        * [.fineChannels](#CoarseChannel+fineChannels) ⇒ [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel)\n        * [.maxResolution](#CoarseChannel+maxResolution) ⇒ [<code>Resolution</code>](#Resolution)\n        * [.dmxValueResolution](#CoarseChannel+dmxValueResolution) ⇒ [<code>Resolution</code>](#Resolution)\n        * [.maxDmxBound](#CoarseChannel+maxDmxBound) ⇒ <code>number</code>\n        * [.hasDefaultValue](#CoarseChannel+hasDefaultValue) ⇒ <code>boolean</code>\n        * [.defaultValue](#CoarseChannel+defaultValue) ⇒ <code>number</code>\n        * [._defaultValuePerResolution](#CoarseChannel+_defaultValuePerResolution) ⇒ <code>Record.&lt;Resolution, number&gt;</code> ℗\n        * [.hasHighlightValue](#CoarseChannel+hasHighlightValue) ⇒ <code>boolean</code>\n        * [.highlightValue](#CoarseChannel+highlightValue) ⇒ <code>number</code>\n        * [._highlightValuePerResolution](#CoarseChannel+_highlightValuePerResolution) ⇒ <code>Record.&lt;Resolution, number&gt;</code> ℗\n        * [.isInverted](#CoarseChannel+isInverted) ⇒ <code>boolean</code>\n        * [.isConstant](#CoarseChannel+isConstant) ⇒ <code>boolean</code>\n        * [.canCrossfade](#CoarseChannel+canCrossfade) ⇒ <code>boolean</code>\n        * [.precedence](#CoarseChannel+precedence) ⇒ <code>&#x27;HTP&#x27;</code> \\| <code>&#x27;LTP&#x27;</code>\n        * [.switchingChannelAliases](#CoarseChannel+switchingChannelAliases) ⇒ <code>Array.&lt;string&gt;</code>\n        * [.switchingChannels](#CoarseChannel+switchingChannels) ⇒ [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel)\n        * [.switchToChannelKeys](#CoarseChannel+switchToChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n        * [.capabilities](#CoarseChannel+capabilities) ⇒ [<code>Array.&lt;Capability&gt;</code>](#Capability)\n        * [.isHelpWanted](#CoarseChannel+isHelpWanted) ⇒ <code>boolean</code>\n        * [.key](#AbstractChannel+key) ⇒ <code>string</code>\n        * [.uniqueName](#AbstractChannel+uniqueName) ⇒ <code>string</code>\n        * [.pixelKey](#AbstractChannel+pixelKey) ⇒ <code>string</code> \\| <code>null</code>\n        * [.ensureProperResolution(uncheckedResolution)](#CoarseChannel+ensureProperResolution)\n        * [.getResolutionInMode(mode, switchingChannelBehavior)](#CoarseChannel+getResolutionInMode) ⇒ [<code>Resolution</code>](#Resolution)\n        * [.getDefaultValueWithResolution(desiredResolution)](#CoarseChannel+getDefaultValueWithResolution) ⇒ <code>number</code>\n        * [.getHighlightValueWithResolution(desiredResolution)](#CoarseChannel+getHighlightValueWithResolution) ⇒ <code>number</code>\n    * _static_\n        * [.RESOLUTION_8BIT](#CoarseChannel.RESOLUTION_8BIT) ⇒ [<code>Resolution</code>](#Resolution)\n        * [.RESOLUTION_16BIT](#CoarseChannel.RESOLUTION_16BIT) ⇒ [<code>Resolution</code>](#Resolution)\n        * [.RESOLUTION_24BIT](#CoarseChannel.RESOLUTION_24BIT) ⇒ [<code>Resolution</code>](#Resolution)\n        * [.RESOLUTION_32BIT](#CoarseChannel.RESOLUTION_32BIT) ⇒ [<code>Resolution</code>](#Resolution)\n\n<a name=\"new_CoarseChannel_new\"></a>\n\n### new CoarseChannel(key, jsonObject, fixture)\nCreate a new CoarseChannel instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| key | <code>string</code> | The channel's identifier, must be unique in the fixture. |\n| jsonObject | <code>object</code> | The channel data from the fixture's JSON. |\n| fixture | [<code>Fixture</code>](#Fixture) | The fixture instance this channel is associated to. |\n\n<a name=\"CoarseChannel+jsonObject\"></a>\n\n### coarseChannel.jsonObject ⇒ <code>object</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>object</code> - The channel data from the fixture's JSON.  \n<a name=\"CoarseChannel+fixture\"></a>\n\n### coarseChannel.fixture ⇒ [<code>Fixture</code>](#Fixture)\nOverrides [`AbstractChannel.fixture`](#AbstractChannel+fixture).\n\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Overrides**: [<code>fixture</code>](#AbstractChannel+fixture)  \n**Returns**: [<code>Fixture</code>](#Fixture) - The fixture instance this channel is associated to.  \n<a name=\"CoarseChannel+name\"></a>\n\n### coarseChannel.name ⇒ <code>string</code>\nOverrides [`AbstractChannel.name`](#AbstractChannel+name).\n\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Overrides**: [<code>name</code>](#AbstractChannel+name)  \n**Returns**: <code>string</code> - The channel name if present or else the channel key.  \n<a name=\"CoarseChannel+type\"></a>\n\n### coarseChannel.type ⇒ <code>string</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>string</code> - The channel type, derived from the channel's capability types.  \n<a name=\"CoarseChannel+color\"></a>\n\n### coarseChannel.color ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>string</code> \\| <code>null</code> - The color of an included ColorIntensity capability, null if there's no such capability.  \n<a name=\"CoarseChannel+fineChannelAliases\"></a>\n\n### coarseChannel.fineChannelAliases ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>Array.&lt;string&gt;</code> - This channel's fine channel aliases, ordered by resolution (coarsest first).  \n<a name=\"CoarseChannel+fineChannels\"></a>\n\n### coarseChannel.fineChannels ⇒ [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel)\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel) - This channel's fine channels, ordered by resolution (coarsest first).  \n<a name=\"CoarseChannel+maxResolution\"></a>\n\n### coarseChannel.maxResolution ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Resolution</code>](#Resolution) - How fine this channel can be used at its maximum. Equals the amount of coarse and fine channels.  \n<a name=\"CoarseChannel+dmxValueResolution\"></a>\n\n### coarseChannel.dmxValueResolution ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Resolution</code>](#Resolution) - How fine this channel is declared in the JSON data. Defaults to [maxResolution](#CoarseChannel+maxResolution).  \n<a name=\"CoarseChannel+maxDmxBound\"></a>\n\n### coarseChannel.maxDmxBound ⇒ <code>number</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>number</code> - The maximum DMX value in the highest possible resolution. E.g. 65535 for a 16bit channel.  \n<a name=\"CoarseChannel+hasDefaultValue\"></a>\n\n### coarseChannel.hasDefaultValue ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>boolean</code> - Whether this channel has a defaultValue.  \n<a name=\"CoarseChannel+defaultValue\"></a>\n\n### coarseChannel.defaultValue ⇒ <code>number</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>number</code> - The DMX value this channel initially should be set to. Specified in the finest possible resolution. Defaults to 0.  \n<a name=\"CoarseChannel+_defaultValuePerResolution\"></a>\n\n### coarseChannel.\\_defaultValuePerResolution ⇒ <code>Record.&lt;Resolution, number&gt;</code> ℗\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>Record.&lt;Resolution, number&gt;</code> - The default DMX value of this channel in the given resolution, for all resolutions up to the channel's maximum resolution.  \n**Access**: private  \n<a name=\"CoarseChannel+hasHighlightValue\"></a>\n\n### coarseChannel.hasHighlightValue ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>boolean</code> - Whether this channel has a highlightValue.  \n<a name=\"CoarseChannel+highlightValue\"></a>\n\n### coarseChannel.highlightValue ⇒ <code>number</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>number</code> - A DMX value that \"highlights\" the function of this channel. Specified in the finest possible resolution. Defaults to the highest possible DMX value.  \n<a name=\"CoarseChannel+_highlightValuePerResolution\"></a>\n\n### coarseChannel.\\_highlightValuePerResolution ⇒ <code>Record.&lt;Resolution, number&gt;</code> ℗\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>Record.&lt;Resolution, number&gt;</code> - The highlight DMX value of this channel in the given resolution, for all resolutions up to the channel's maximum resolution.  \n**Access**: private  \n<a name=\"CoarseChannel+isInverted\"></a>\n\n### coarseChannel.isInverted ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>boolean</code> - Whether a fader for this channel should be displayed upside down.  \n<a name=\"CoarseChannel+isConstant\"></a>\n\n### coarseChannel.isConstant ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>boolean</code> - Whether this channel should constantly stay at the same value.  \n<a name=\"CoarseChannel+canCrossfade\"></a>\n\n### coarseChannel.canCrossfade ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>boolean</code> - Whether switching from one DMX value to another in this channel can be faded smoothly.  \n<a name=\"CoarseChannel+precedence\"></a>\n\n### coarseChannel.precedence ⇒ <code>&#x27;HTP&#x27;</code> \\| <code>&#x27;LTP&#x27;</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>&#x27;HTP&#x27;</code> \\| <code>&#x27;LTP&#x27;</code> - The channel's behavior when being affected by multiple faders: HTP (Highest Takes Precedent) or LTP (Latest Takes Precedent).  \n<a name=\"CoarseChannel+switchingChannelAliases\"></a>\n\n### coarseChannel.switchingChannelAliases ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Aliases of the switching channels defined by this channel, ordered by appearance in the JSON.  \n<a name=\"CoarseChannel+switchingChannels\"></a>\n\n### coarseChannel.switchingChannels ⇒ [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel)\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel) - Switching channels defined by this channel, ordered by appearance in the JSON.  \n<a name=\"CoarseChannel+switchToChannelKeys\"></a>\n\n### coarseChannel.switchToChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>Array.&lt;string&gt;</code> - The keys of the channels to which the switching channels defined by this channel can be switched to.  \n<a name=\"CoarseChannel+capabilities\"></a>\n\n### coarseChannel.capabilities ⇒ [<code>Array.&lt;Capability&gt;</code>](#Capability)\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Array.&lt;Capability&gt;</code>](#Capability) - All capabilities of this channel, ordered by DMX range.  \n<a name=\"CoarseChannel+isHelpWanted\"></a>\n\n### coarseChannel.isHelpWanted ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>boolean</code> - True if help is needed in a capability of this channel, false otherwise.  \n<a name=\"AbstractChannel+key\"></a>\n\n### coarseChannel.key ⇒ <code>string</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Overrides**: [<code>key</code>](#AbstractChannel+key)  \n**Returns**: <code>string</code> - The channel key.  \n<a name=\"AbstractChannel+uniqueName\"></a>\n\n### coarseChannel.uniqueName ⇒ <code>string</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Overrides**: [<code>uniqueName</code>](#AbstractChannel+uniqueName)  \n**Returns**: <code>string</code> - Unique version of this channel's name.  \n**See**: [uniqueChannelNames](#Fixture+uniqueChannelNames)  \n<a name=\"AbstractChannel+pixelKey\"></a>\n\n### coarseChannel.pixelKey ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Overrides**: [<code>pixelKey</code>](#AbstractChannel+pixelKey)  \n**Returns**: <code>string</code> \\| <code>null</code> - The key of the pixel (group) that this channel is associated to. Defaults to null.  \n<a name=\"CoarseChannel+ensureProperResolution\"></a>\n\n### coarseChannel.ensureProperResolution(uncheckedResolution)\nChecks the given resolution if it can safely be used in this channel.\n\n**Kind**: instance method of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Throws**:\n\n- <code>RangeError</code> If the given resolution is invalid in this channel.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| uncheckedResolution | [<code>Resolution</code>](#Resolution) | The resolution to be checked. |\n\n<a name=\"CoarseChannel+getResolutionInMode\"></a>\n\n### coarseChannel.getResolutionInMode(mode, switchingChannelBehavior) ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: instance method of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Resolution</code>](#Resolution) - How fine this channel is used in the given mode. 0 if the channel isn't used at all.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| mode | [<code>Mode</code>](#Mode) | The mode in which this channel is used. |\n| switchingChannelBehavior | [<code>SwitchingChannelBehavior</code>](#SwitchingChannelBehavior) | How switching channels are treated, see [getChannelIndex](#Mode+getChannelIndex). |\n\n<a name=\"CoarseChannel+getDefaultValueWithResolution\"></a>\n\n### coarseChannel.getDefaultValueWithResolution(desiredResolution) ⇒ <code>number</code>\n**Kind**: instance method of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>number</code> - The DMX value this channel initially should be set to, scaled to match the given resolution.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| desiredResolution | [<code>Resolution</code>](#Resolution) | The grade of resolution the defaultValue should be scaled to. |\n\n<a name=\"CoarseChannel+getHighlightValueWithResolution\"></a>\n\n### coarseChannel.getHighlightValueWithResolution(desiredResolution) ⇒ <code>number</code>\n**Kind**: instance method of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: <code>number</code> - A DMX value that \"highlights\" the function of this channel, scaled to match the given resolution.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| desiredResolution | [<code>Resolution</code>](#Resolution) | The grade of resolution the highlightValue should be scaled to. |\n\n<a name=\"CoarseChannel.RESOLUTION_8BIT\"></a>\n\n### CoarseChannel.RESOLUTION\\_8BIT ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: static property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Resolution</code>](#Resolution) - Resolution of an 8bit channel.  \n<a name=\"CoarseChannel.RESOLUTION_16BIT\"></a>\n\n### CoarseChannel.RESOLUTION\\_16BIT ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: static property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Resolution</code>](#Resolution) - Resolution of a 16bit channel.  \n<a name=\"CoarseChannel.RESOLUTION_24BIT\"></a>\n\n### CoarseChannel.RESOLUTION\\_24BIT ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: static property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Resolution</code>](#Resolution) - Resolution of a 24bit channel.  \n<a name=\"CoarseChannel.RESOLUTION_32BIT\"></a>\n\n### CoarseChannel.RESOLUTION\\_32BIT ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: static property of [<code>CoarseChannel</code>](#CoarseChannel)  \n**Returns**: [<code>Resolution</code>](#Resolution) - Resolution of a 32bit channel.  \n<a name=\"Entity\"></a>\n\n## Entity\nA physical entity with numerical value and unit information.\n\n**Kind**: global class  \n\n* [Entity](#Entity)\n    * [new Entity(number, unit, keyword)](#new_Entity_new)\n    * _instance_\n        * [.number](#Entity+number) ⇒ <code>number</code>\n        * [.unit](#Entity+unit) ⇒ <code>string</code>\n        * [.keyword](#Entity+keyword) ⇒ <code>string</code> \\| <code>null</code>\n        * [.baseUnitEntity](#Entity+baseUnitEntity) ⇒ [<code>Entity</code>](#Entity)\n        * [.valueOf()](#Entity+valueOf) ⇒ <code>number</code>\n        * [.toString()](#Entity+toString) ⇒ <code>string</code>\n        * [.equals(anotherEntity)](#Entity+equals) ⇒ <code>boolean</code>\n    * _static_\n        * [.createFromEntityString(entityString)](#Entity.createFromEntityString) ⇒ [<code>Entity</code>](#Entity)\n\n<a name=\"new_Entity_new\"></a>\n\n### new Entity(number, unit, keyword)\nCreates a new Entity instance.\n\n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| number | <code>number</code> |  | The numerical value. |\n| unit | <code>string</code> |  | The unit symbol, e.g. 'Hz'. Must be the same as in the schema. |\n| keyword | <code>string</code> \\| <code>null</code> | <code>null</code> | The keyword if defined using a keyword. Optional. |\n\n<a name=\"Entity+number\"></a>\n\n### entity.number ⇒ <code>number</code>\n**Kind**: instance property of [<code>Entity</code>](#Entity)  \n**Returns**: <code>number</code> - The numerical value of this entity.  \n<a name=\"Entity+unit\"></a>\n\n### entity.unit ⇒ <code>string</code>\n**Kind**: instance property of [<code>Entity</code>](#Entity)  \n**Returns**: <code>string</code> - The unit symbol, like \"Hz\" or \"%\".  \n<a name=\"Entity+keyword\"></a>\n\n### entity.keyword ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Entity</code>](#Entity)  \n**Returns**: <code>string</code> \\| <code>null</code> - The used keyword, or null if no keyword was used.  \n<a name=\"Entity+baseUnitEntity\"></a>\n\n### entity.baseUnitEntity ⇒ [<code>Entity</code>](#Entity)\n**Kind**: instance property of [<code>Entity</code>](#Entity)  \n**Returns**: [<code>Entity</code>](#Entity) - An entity of the same value, but scaled to the base unit. Returns the entity itself if it is already in the base unit.  \n<a name=\"Entity+valueOf\"></a>\n\n### entity.valueOf() ⇒ <code>number</code>\nUsed to allow comparing like `entity1 < entity2`\n\n**Kind**: instance method of [<code>Entity</code>](#Entity)  \n**Returns**: <code>number</code> - The numerical value of this entity.  \n<a name=\"Entity+toString\"></a>\n\n### entity.toString() ⇒ <code>string</code>\n**Kind**: instance method of [<code>Entity</code>](#Entity)  \n**Returns**: <code>string</code> - The entity string that could be used in the fixture's JSON data.  \n<a name=\"Entity+equals\"></a>\n\n### entity.equals(anotherEntity) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>Entity</code>](#Entity)  \n**Returns**: <code>boolean</code> - Whether this entity exactly equals the given one.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| anotherEntity | [<code>Entity</code>](#Entity) | Another Entity instance to compare with. |\n\n<a name=\"Entity.createFromEntityString\"></a>\n\n### Entity.createFromEntityString(entityString) ⇒ [<code>Entity</code>](#Entity)\n**Kind**: static method of [<code>Entity</code>](#Entity)  \n**Returns**: [<code>Entity</code>](#Entity) - A new entity from the given string.  \n**Throws**:\n\n- <code>Error</code> If the entity string is invalid.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| entityString | <code>string</code> | The string for a single entity value from the JSON data. May also be a keyword. |\n\n<a name=\"FineChannel\"></a>\n\n## FineChannel ⇐ [<code>AbstractChannel</code>](#AbstractChannel)\nRepresents a finer channel of a 16+ bit channel.\nAlso called LSB (least significant byte) channel.\n\n**Kind**: global class  \n**Extends**: [<code>AbstractChannel</code>](#AbstractChannel)  \n\n* [FineChannel](#FineChannel) ⇐ [<code>AbstractChannel</code>](#AbstractChannel)\n    * [new FineChannel(key, coarseChannel)](#new_FineChannel_new)\n    * [.coarseChannel](#FineChannel+coarseChannel) ⇒ [<code>CoarseChannel</code>](#CoarseChannel)\n    * [.coarserChannel](#FineChannel+coarserChannel) ⇒ [<code>CoarseChannel</code>](#CoarseChannel) \\| [<code>FineChannel</code>](#FineChannel)\n    * [.name](#FineChannel+name) ⇒ <code>string</code>\n    * [.fixture](#FineChannel+fixture) ⇒ [<code>Fixture</code>](#Fixture)\n    * [.resolution](#FineChannel+resolution) ⇒ [<code>Resolution</code>](#Resolution)\n    * [.defaultValue](#FineChannel+defaultValue) ⇒ <code>number</code>\n    * [.key](#AbstractChannel+key) ⇒ <code>string</code>\n    * [.uniqueName](#AbstractChannel+uniqueName) ⇒ <code>string</code>\n    * [.pixelKey](#AbstractChannel+pixelKey) ⇒ <code>string</code> \\| <code>null</code>\n\n<a name=\"new_FineChannel_new\"></a>\n\n### new FineChannel(key, coarseChannel)\nCreates a new FineChannel instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| key | <code>string</code> | The fine channel alias as defined in the coarse channel. |\n| coarseChannel | [<code>CoarseChannel</code>](#CoarseChannel) | The coarse (MSB) channel. |\n\n<a name=\"FineChannel+coarseChannel\"></a>\n\n### fineChannel.coarseChannel ⇒ [<code>CoarseChannel</code>](#CoarseChannel)\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Returns**: [<code>CoarseChannel</code>](#CoarseChannel) - The coarse (MSB) channel.  \n<a name=\"FineChannel+coarserChannel\"></a>\n\n### fineChannel.coarserChannel ⇒ [<code>CoarseChannel</code>](#CoarseChannel) \\| [<code>FineChannel</code>](#FineChannel)\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Returns**: [<code>CoarseChannel</code>](#CoarseChannel) \\| [<code>FineChannel</code>](#FineChannel) - The next coarser channel. May also be a fine channel, if this fine channel's resolution is 24bit or higher.  \n<a name=\"FineChannel+name\"></a>\n\n### fineChannel.name ⇒ <code>string</code>\nOverrides [`AbstractChannel.name`](#AbstractChannel+name).\n\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Overrides**: [<code>name</code>](#AbstractChannel+name)  \n**Returns**: <code>string</code> - A generated channel name, based upon the coarse channel's name.  \n<a name=\"FineChannel+fixture\"></a>\n\n### fineChannel.fixture ⇒ [<code>Fixture</code>](#Fixture)\nOverrides [`AbstractChannel.fixture`](#AbstractChannel+fixture).\n\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Overrides**: [<code>fixture</code>](#AbstractChannel+fixture)  \n**Returns**: [<code>Fixture</code>](#Fixture) - The fixture this channel belongs to.  \n<a name=\"FineChannel+resolution\"></a>\n\n### fineChannel.resolution ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Returns**: [<code>Resolution</code>](#Resolution) - The resolution of this fine channel. E.g. 2 (16bit) for the first fine channel, 3 (24bit) for the second fine channel, etc.  \n<a name=\"FineChannel+defaultValue\"></a>\n\n### fineChannel.defaultValue ⇒ <code>number</code>\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Returns**: <code>number</code> - The DMX value (from 0 to 255) this channel should be set to by default.  \n<a name=\"AbstractChannel+key\"></a>\n\n### fineChannel.key ⇒ <code>string</code>\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Overrides**: [<code>key</code>](#AbstractChannel+key)  \n**Returns**: <code>string</code> - The channel key.  \n<a name=\"AbstractChannel+uniqueName\"></a>\n\n### fineChannel.uniqueName ⇒ <code>string</code>\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Overrides**: [<code>uniqueName</code>](#AbstractChannel+uniqueName)  \n**Returns**: <code>string</code> - Unique version of this channel's name.  \n**See**: [uniqueChannelNames](#Fixture+uniqueChannelNames)  \n<a name=\"AbstractChannel+pixelKey\"></a>\n\n### fineChannel.pixelKey ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>FineChannel</code>](#FineChannel)  \n**Overrides**: [<code>pixelKey</code>](#AbstractChannel+pixelKey)  \n**Returns**: <code>string</code> \\| <code>null</code> - The key of the pixel (group) that this channel is associated to. Defaults to null.  \n<a name=\"Fixture\"></a>\n\n## Fixture\nA physical DMX device.\n\n**Kind**: global class  \n\n* [Fixture](#Fixture)\n    * [new Fixture(manufacturer, key, jsonObject)](#new_Fixture_new)\n    * [.manufacturer](#Fixture+manufacturer) ⇒ [<code>Manufacturer</code>](#Manufacturer)\n    * [.key](#Fixture+key) ⇒ <code>string</code>\n    * [.jsonObject](#Fixture+jsonObject) ⇒ <code>object</code>\n    * [.url](#Fixture+url) ⇒ <code>string</code>\n    * [.name](#Fixture+name) ⇒ <code>string</code>\n    * [.hasShortName](#Fixture+hasShortName) ⇒ <code>boolean</code>\n    * [.shortName](#Fixture+shortName) ⇒ <code>string</code>\n    * [.categories](#Fixture+categories) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.mainCategory](#Fixture+mainCategory) ⇒ <code>string</code>\n    * [.meta](#Fixture+meta) ⇒ [<code>Meta</code>](#Meta)\n    * [.hasComment](#Fixture+hasComment) ⇒ <code>boolean</code>\n    * [.comment](#Fixture+comment) ⇒ <code>string</code>\n    * [.helpWanted](#Fixture+helpWanted) ⇒ <code>string</code> \\| <code>null</code>\n    * [.isHelpWanted](#Fixture+isHelpWanted) ⇒ <code>boolean</code>\n    * [.isCapabilityHelpWanted](#Fixture+isCapabilityHelpWanted) ⇒ <code>boolean</code>\n    * [.links](#Fixture+links) ⇒ <code>Record.&lt;string, Array.&lt;string&gt;&gt;</code> \\| <code>null</code>\n    * [.rdm](#Fixture+rdm) ⇒ <code>object</code> \\| <code>null</code>\n    * [.physical](#Fixture+physical) ⇒ [<code>Physical</code>](#Physical) \\| <code>null</code>\n    * [.matrix](#Fixture+matrix) ⇒ [<code>Matrix</code>](#Matrix) \\| <code>null</code>\n    * [.wheels](#Fixture+wheels) ⇒ [<code>Array.&lt;Wheel&gt;</code>](#Wheel)\n    * [._wheelByName](#Fixture+_wheelByName) ⇒ <code>Record.&lt;string, Wheel&gt;</code> ℗\n    * [.uniqueChannelNames](#Fixture+uniqueChannelNames) ⇒ <code>Record.&lt;string, string&gt;</code>\n    * [.availableChannelKeys](#Fixture+availableChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.availableChannels](#Fixture+availableChannels) ⇒ [<code>Array.&lt;CoarseChannel&gt;</code>](#CoarseChannel)\n    * [.coarseChannelKeys](#Fixture+coarseChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.coarseChannels](#Fixture+coarseChannels) ⇒ [<code>Array.&lt;CoarseChannel&gt;</code>](#CoarseChannel)\n    * [.fineChannelAliases](#Fixture+fineChannelAliases) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.fineChannels](#Fixture+fineChannels) ⇒ [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel)\n    * [.switchingChannelAliases](#Fixture+switchingChannelAliases) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.switchingChannels](#Fixture+switchingChannels) ⇒ [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel)\n    * [.templateChannelKeys](#Fixture+templateChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.templateChannels](#Fixture+templateChannels) ⇒ [<code>Array.&lt;TemplateChannel&gt;</code>](#TemplateChannel)\n    * [._templateChannelByKey](#Fixture+_templateChannelByKey) ⇒ <code>Record.&lt;string, TemplateChannel&gt;</code> ℗\n    * [.matrixChannelKeys](#Fixture+matrixChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.matrixChannels](#Fixture+matrixChannels) ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n    * [.nullChannelKeys](#Fixture+nullChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.nullChannels](#Fixture+nullChannels) ⇒ [<code>Array.&lt;NullChannel&gt;</code>](#NullChannel)\n    * [.allChannelKeys](#Fixture+allChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.allChannels](#Fixture+allChannels) ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n    * [.allChannelsByKey](#Fixture+allChannelsByKey) ⇒ <code>Record.&lt;string, AbstractChannel&gt;</code>\n    * [.capabilities](#Fixture+capabilities) ⇒ [<code>Array.&lt;Capability&gt;</code>](#Capability)\n    * [.modes](#Fixture+modes) ⇒ [<code>Array.&lt;Mode&gt;</code>](#Mode)\n    * [.getLinksOfType(type)](#Fixture+getLinksOfType) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.getWheelByName(wheelName)](#Fixture+getWheelByName) ⇒ [<code>Wheel</code>](#Wheel) \\| <code>null</code>\n    * [.getTemplateChannelByKey(channelKey)](#Fixture+getTemplateChannelByKey) ⇒ [<code>TemplateChannel</code>](#TemplateChannel) \\| <code>null</code>\n    * [.getChannelByKey(key)](#Fixture+getChannelByKey) ⇒ [<code>AbstractChannel</code>](#AbstractChannel) \\| <code>null</code>\n\n<a name=\"new_Fixture_new\"></a>\n\n### new Fixture(manufacturer, key, jsonObject)\nCreate a new Fixture instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| manufacturer | [<code>Manufacturer</code>](#Manufacturer) | A Manufacturer instance. |\n| key | <code>string</code> | The fixture's unique key. Equals to filename without '.json'. |\n| jsonObject | <code>object</code> | The fixture's parsed JSON data. |\n\n<a name=\"Fixture+manufacturer\"></a>\n\n### fixture.manufacturer ⇒ [<code>Manufacturer</code>](#Manufacturer)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Manufacturer</code>](#Manufacturer) - The fixture's manufacturer.  \n<a name=\"Fixture+key\"></a>\n\n### fixture.key ⇒ <code>string</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>string</code> - The fixture's unique key. Equals to filename without '.json'.  \n<a name=\"Fixture+jsonObject\"></a>\n\n### fixture.jsonObject ⇒ <code>object</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>object</code> - The fixture's parsed JSON data.  \n<a name=\"Fixture+url\"></a>\n\n### fixture.url ⇒ <code>string</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>string</code> - An URL pointing to the fixture's page on the Open Fixture Library website.  \n<a name=\"Fixture+name\"></a>\n\n### fixture.name ⇒ <code>string</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>string</code> - The fixture's product name.  \n<a name=\"Fixture+hasShortName\"></a>\n\n### fixture.hasShortName ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>boolean</code> - Whether a short name is defined for this fixture.  \n<a name=\"Fixture+shortName\"></a>\n\n### fixture.shortName ⇒ <code>string</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>string</code> - A globally unique and as short as possible product name, defaults to name.  \n<a name=\"Fixture+categories\"></a>\n\n### fixture.categories ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - The fixture's categories with the most applicable one first.  \n<a name=\"Fixture+mainCategory\"></a>\n\n### fixture.mainCategory ⇒ <code>string</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>string</code> - The fixture's most applicable category. Equals to first item of categories.  \n<a name=\"Fixture+meta\"></a>\n\n### fixture.meta ⇒ [<code>Meta</code>](#Meta)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Meta</code>](#Meta) - A Meta instance providing information like author or create date.  \n<a name=\"Fixture+hasComment\"></a>\n\n### fixture.hasComment ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>boolean</code> - Whether a comment is defined for this fixture.  \n<a name=\"Fixture+comment\"></a>\n\n### fixture.comment ⇒ <code>string</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>string</code> - A comment about the fixture (often a note about an incorrectness in the manual). Defaults to an empty string.  \n<a name=\"Fixture+helpWanted\"></a>\n\n### fixture.helpWanted ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>string</code> \\| <code>null</code> - A string describing the help that is needed for this fixture, or null if no help is needed.  \n<a name=\"Fixture+isHelpWanted\"></a>\n\n### fixture.isHelpWanted ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>boolean</code> - True if help is needed in this fixture (maybe in a capability), false otherwise.  \n<a name=\"Fixture+isCapabilityHelpWanted\"></a>\n\n### fixture.isCapabilityHelpWanted ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>boolean</code> - True if help is needed in a capability, false otherwise.  \n<a name=\"Fixture+links\"></a>\n\n### fixture.links ⇒ <code>Record.&lt;string, Array.&lt;string&gt;&gt;</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Record.&lt;string, Array.&lt;string&gt;&gt;</code> \\| <code>null</code> - An object with URL arrays, organized by link type, or null if no links are available for this fixture.  \n<a name=\"Fixture+rdm\"></a>\n\n### fixture.rdm ⇒ <code>object</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>object</code> \\| <code>null</code> - Information about the RDM functionality of this fixture. Defaults to null.  \n**Properties**\n\n| Name | Type | Description |\n| --- | --- | --- |\n| modelId | <code>number</code> | The RDM model/product id of the fixture, given in decimal format. |\n| softwareVersion | <code>string</code> \\| <code>null</code> | The software version used as reference in this fixture definition. |\n\n<a name=\"Fixture+physical\"></a>\n\n### fixture.physical ⇒ [<code>Physical</code>](#Physical) \\| <code>null</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Physical</code>](#Physical) \\| <code>null</code> - The general physical information for the fixture, may be overridden by modes.  \n<a name=\"Fixture+matrix\"></a>\n\n### fixture.matrix ⇒ [<code>Matrix</code>](#Matrix) \\| <code>null</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Matrix</code>](#Matrix) \\| <code>null</code> - The matrix information for this fixture.  \n<a name=\"Fixture+wheels\"></a>\n\n### fixture.wheels ⇒ [<code>Array.&lt;Wheel&gt;</code>](#Wheel)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;Wheel&gt;</code>](#Wheel) - The fixture's wheels as [Wheel](#Wheel) instances.  \n<a name=\"Fixture+_wheelByName\"></a>\n\n### fixture.\\_wheelByName ⇒ <code>Record.&lt;string, Wheel&gt;</code> ℗\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Record.&lt;string, Wheel&gt;</code> - This fixture's wheel names pointing to the respective Wheel instance.  \n**Access**: private  \n<a name=\"Fixture+uniqueChannelNames\"></a>\n\n### fixture.uniqueChannelNames ⇒ <code>Record.&lt;string, string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Record.&lt;string, string&gt;</code> - Channel keys from [allChannelKeys](#Fixture+allChannelKeys) pointing to unique versions of their channel names.  \n<a name=\"Fixture+availableChannelKeys\"></a>\n\n### fixture.availableChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Coarse channels from the fixture definition's `availableChannels` section. Ordered by appearance.  \n<a name=\"Fixture+availableChannels\"></a>\n\n### fixture.availableChannels ⇒ [<code>Array.&lt;CoarseChannel&gt;</code>](#CoarseChannel)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;CoarseChannel&gt;</code>](#CoarseChannel) - Coarse channels from the fixture definition's `availableChannels` section. Ordered by appearance.  \n<a name=\"Fixture+coarseChannelKeys\"></a>\n\n### fixture.coarseChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Coarse channels' keys, including matrix channels' keys. If possible, ordered by appearance.  \n<a name=\"Fixture+coarseChannels\"></a>\n\n### fixture.coarseChannels ⇒ [<code>Array.&lt;CoarseChannel&gt;</code>](#CoarseChannel)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;CoarseChannel&gt;</code>](#CoarseChannel) - Coarse channels, including matrix channels. If possible, ordered by appearance.  \n<a name=\"Fixture+fineChannelAliases\"></a>\n\n### fixture.fineChannelAliases ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All fine channels' aliases, including matrix fine channels' aliases. If possible, ordered by appearance.  \n<a name=\"Fixture+fineChannels\"></a>\n\n### fixture.fineChannels ⇒ [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel) - All fine channels, including matrix fine channels. If possible, ordered by appearance.  \n<a name=\"Fixture+switchingChannelAliases\"></a>\n\n### fixture.switchingChannelAliases ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All switching channels' aliases, including matrix switching channels' aliases. If possible, ordered by appearance.  \n<a name=\"Fixture+switchingChannels\"></a>\n\n### fixture.switchingChannels ⇒ [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel) - All switching channels, including matrix switching channels. If possible, ordered by appearance.  \n<a name=\"Fixture+templateChannelKeys\"></a>\n\n### fixture.templateChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\nTemplate channels are used to automatically generate channels.\n\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All template channel keys from the fixture definition's `templateChannels` section. Ordered by appearance.  \n<a name=\"Fixture+templateChannels\"></a>\n\n### fixture.templateChannels ⇒ [<code>Array.&lt;TemplateChannel&gt;</code>](#TemplateChannel)\nTemplate channels are used to automatically generate channels.\n\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;TemplateChannel&gt;</code>](#TemplateChannel) - TemplateChannel instances for all template channels from the fixture definition's `templateChannels` section. Ordered by appearance.  \n<a name=\"Fixture+_templateChannelByKey\"></a>\n\n### fixture.\\_templateChannelByKey ⇒ <code>Record.&lt;string, TemplateChannel&gt;</code> ℗\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Record.&lt;string, TemplateChannel&gt;</code> - This fixture's template channel keys pointing to the respective template channel.  \n**Access**: private  \n<a name=\"Fixture+matrixChannelKeys\"></a>\n\n### fixture.matrixChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Keys of all resolved matrix channels.  \n<a name=\"Fixture+matrixChannels\"></a>\n\n### fixture.matrixChannels ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel) - All (resolved) channels with `pixelKey` information (including fine and switching channels).  \n<a name=\"Fixture+nullChannelKeys\"></a>\n\n### fixture.nullChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All null channels' keys.  \n<a name=\"Fixture+nullChannels\"></a>\n\n### fixture.nullChannels ⇒ [<code>Array.&lt;NullChannel&gt;</code>](#NullChannel)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;NullChannel&gt;</code>](#NullChannel) - Automatically generated null channels.  \n<a name=\"Fixture+allChannelKeys\"></a>\n\n### fixture.allChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All channel keys used in this fixture, including resolved matrix channels' keys. If possible, ordered by appearance.  \n<a name=\"Fixture+allChannels\"></a>\n\n### fixture.allChannels ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel) - All channels used in this fixture, including resolved matrix channels. If possible, ordered by appearance.  \n<a name=\"Fixture+allChannelsByKey\"></a>\n\n### fixture.allChannelsByKey ⇒ <code>Record.&lt;string, AbstractChannel&gt;</code>\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Record.&lt;string, AbstractChannel&gt;</code> - All channel keys used in this fixture pointing to the respective channel, including matrix channels. If possible, ordered by appearance.  \n<a name=\"Fixture+capabilities\"></a>\n\n### fixture.capabilities ⇒ [<code>Array.&lt;Capability&gt;</code>](#Capability)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;Capability&gt;</code>](#Capability) - All available channels' and template channels' capabilities.  \n<a name=\"Fixture+modes\"></a>\n\n### fixture.modes ⇒ [<code>Array.&lt;Mode&gt;</code>](#Mode)\n**Kind**: instance property of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Array.&lt;Mode&gt;</code>](#Mode) - The fixture's modes.  \n<a name=\"Fixture+getLinksOfType\"></a>\n\n### fixture.getLinksOfType(type) ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance method of [<code>Fixture</code>](#Fixture)  \n**Returns**: <code>Array.&lt;string&gt;</code> - An array of URLs of the specified type (may be empty).  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| type | <code>string</code> | The type of the links that should be returned. |\n\n<a name=\"Fixture+getWheelByName\"></a>\n\n### fixture.getWheelByName(wheelName) ⇒ [<code>Wheel</code>](#Wheel) \\| <code>null</code>\n**Kind**: instance method of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>Wheel</code>](#Wheel) \\| <code>null</code> - The wheel with the given name, or null if no wheel with the given name exists.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| wheelName | <code>string</code> | The name of the wheel. |\n\n<a name=\"Fixture+getTemplateChannelByKey\"></a>\n\n### fixture.getTemplateChannelByKey(channelKey) ⇒ [<code>TemplateChannel</code>](#TemplateChannel) \\| <code>null</code>\nSearches the template channel with the given key. Fine and switching template channel aliases *can't* be found.\n\n**Kind**: instance method of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>TemplateChannel</code>](#TemplateChannel) \\| <code>null</code> - The corresponding template channel.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| channelKey | <code>string</code> | The template channel's key |\n\n<a name=\"Fixture+getChannelByKey\"></a>\n\n### fixture.getChannelByKey(key) ⇒ [<code>AbstractChannel</code>](#AbstractChannel) \\| <code>null</code>\n**Kind**: instance method of [<code>Fixture</code>](#Fixture)  \n**Returns**: [<code>AbstractChannel</code>](#AbstractChannel) \\| <code>null</code> - The found channel, null if not found.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| key | <code>string</code> | The channel's key. |\n\n<a name=\"Manufacturer\"></a>\n\n## Manufacturer\nA company or brand that produces fixtures. A fixture is associated to exactly one manufacturer.\n\n**Kind**: global class  \n\n* [Manufacturer](#Manufacturer)\n    * [new Manufacturer(key, jsonObject)](#new_Manufacturer_new)\n    * [.name](#Manufacturer+name) ⇒ <code>string</code>\n    * [.comment](#Manufacturer+comment) ⇒ <code>string</code>\n    * [.hasComment](#Manufacturer+hasComment) ⇒ <code>boolean</code>\n    * [.website](#Manufacturer+website) ⇒ <code>string</code> \\| <code>null</code>\n    * [.rdmId](#Manufacturer+rdmId) ⇒ <code>number</code> \\| <code>null</code>\n\n<a name=\"new_Manufacturer_new\"></a>\n\n### new Manufacturer(key, jsonObject)\nCreates a new Manufacturer instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| key | <code>string</code> | The manufacturer key. Equals to directory name in the fixtures directory. |\n| jsonObject | <code>object</code> | The manufacturer's JSON object. |\n\n<a name=\"Manufacturer+name\"></a>\n\n### manufacturer.name ⇒ <code>string</code>\n**Kind**: instance property of [<code>Manufacturer</code>](#Manufacturer)  \n**Returns**: <code>string</code> - The manufacturer's display name. Often used as prefix of fixture names, e.g. \"cameo\" + \"Hydrabeam 100\".  \n<a name=\"Manufacturer+comment\"></a>\n\n### manufacturer.comment ⇒ <code>string</code>\n**Kind**: instance property of [<code>Manufacturer</code>](#Manufacturer)  \n**Returns**: <code>string</code> - An additional description or explanation, if the name doesn't give enough information. Defaults to an empty string.  \n<a name=\"Manufacturer+hasComment\"></a>\n\n### manufacturer.hasComment ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Manufacturer</code>](#Manufacturer)  \n**Returns**: <code>boolean</code> - Whether this manufacturer has a comment.  \n<a name=\"Manufacturer+website\"></a>\n\n### manufacturer.website ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Manufacturer</code>](#Manufacturer)  \n**Returns**: <code>string</code> \\| <code>null</code> - An URL pointing to the manufacturer's website (with fixture product pages).  \n<a name=\"Manufacturer+rdmId\"></a>\n\n### manufacturer.rdmId ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Manufacturer</code>](#Manufacturer)  \n**Returns**: <code>number</code> \\| <code>null</code> - The id associated to this manufacturer in the RDM protocol.  \n<a name=\"Matrix\"></a>\n\n## Matrix\nContains information of how the pixels in a 1-, 2- or 3-dimensional space are arranged and named.\n\n**Kind**: global class  \n\n* [Matrix](#Matrix)\n    * [new Matrix(jsonObject)](#new_Matrix_new)\n    * [.jsonObject](#Matrix+jsonObject) ⇒ <code>object</code>\n    * [.pixelCount](#Matrix+pixelCount) ⇒ <code>Array.&lt;number&gt;</code>\n    * [.pixelCountX](#Matrix+pixelCountX) ⇒ <code>number</code>\n    * [.pixelCountY](#Matrix+pixelCountY) ⇒ <code>number</code>\n    * [.pixelCountZ](#Matrix+pixelCountZ) ⇒ <code>number</code>\n    * [.definedAxes](#Matrix+definedAxes) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.pixelKeyStructure](#Matrix+pixelKeyStructure) ⇒ <code>Array.&lt;Array.&lt;Array.&lt;string&gt;&gt;&gt;</code>\n    * [.pixelKeys](#Matrix+pixelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.pixelKeyPositions](#Matrix+pixelKeyPositions) ⇒ <code>Record.&lt;string, Array.&lt;number&gt;&gt;</code>\n    * [.pixelGroupKeys](#Matrix+pixelGroupKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.pixelGroups](#Matrix+pixelGroups) ⇒ <code>Record.&lt;string, Array.&lt;string&gt;&gt;</code>\n    * [._getPixelDefaultKeys()](#Matrix+_getPixelDefaultKeys) ⇒ <code>Array.&lt;Array.&lt;Array.&lt;string&gt;&gt;&gt;</code> ℗\n    * [._getPixelDefaultKey(x, y, z)](#Matrix+_getPixelDefaultKey) ⇒ <code>string</code> ℗\n    * [.getPixelKeysByOrder(firstAxis, secondAxis, thirdAxis)](#Matrix+getPixelKeysByOrder) ⇒ <code>Array.&lt;string&gt;</code>\n    * [._pixelKeyFulfillsConstraints(pixelKey, constraints)](#Matrix+_pixelKeyFulfillsConstraints) ⇒ <code>boolean</code>\n\n<a name=\"new_Matrix_new\"></a>\n\n### new Matrix(jsonObject)\n\n| Param | Type | Description |\n| --- | --- | --- |\n| jsonObject | <code>object</code> | The fixture's JSON object containing the matrix information. |\n\n<a name=\"Matrix+jsonObject\"></a>\n\n### matrix.jsonObject ⇒ <code>object</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>object</code> - The fixture's JSON object containing the matrix information.  \n<a name=\"Matrix+pixelCount\"></a>\n\n### matrix.pixelCount ⇒ <code>Array.&lt;number&gt;</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Array.&lt;number&gt;</code> - Amount of pixels in X, Y and Z direction. A horizontal bar with 4 LEDs would be `[4, 1, 1]`, a 5x5 pixel head would be `[5, 5, 1]`.  \n**Throws**:\n\n- <code>ReferenceError</code> If neither `pixelCount` nor `pixelKeys` are defined in the matrix JSON object.\n\n<a name=\"Matrix+pixelCountX\"></a>\n\n### matrix.pixelCountX ⇒ <code>number</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>number</code> - Amount of pixels in X direction.  \n<a name=\"Matrix+pixelCountY\"></a>\n\n### matrix.pixelCountY ⇒ <code>number</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>number</code> - Amount of pixels in Y direction.  \n<a name=\"Matrix+pixelCountZ\"></a>\n\n### matrix.pixelCountZ ⇒ <code>number</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>number</code> - Amount of pixels in Z direction.  \n<a name=\"Matrix+definedAxes\"></a>\n\n### matrix.definedAxes ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Contains each of 'X', 'Y', 'Z' if its respective axis is defined (= if its `pixelCount` is > 1).  \n<a name=\"Matrix+pixelKeyStructure\"></a>\n\n### matrix.pixelKeyStructure ⇒ <code>Array.&lt;Array.&lt;Array.&lt;string&gt;&gt;&gt;</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Array.&lt;Array.&lt;Array.&lt;string&gt;&gt;&gt;</code> - Pixel keys by Z, Y and X position.  \n**Throws**:\n\n- <code>ReferenceError</code> if neither `pixelCount` nor `pixelKeys` are defined in the matrix JSON object.\n\n<a name=\"Matrix+pixelKeys\"></a>\n\n### matrix.pixelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All pixelKeys, ordered alphanumerically (1 < 2 < 10 < alice < bob < carol)  \n<a name=\"Matrix+pixelKeyPositions\"></a>\n\n### matrix.pixelKeyPositions ⇒ <code>Record.&lt;string, Array.&lt;number&gt;&gt;</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Record.&lt;string, Array.&lt;number&gt;&gt;</code> - Each pixelKey pointing to an array of its X/Y/Z position  \n<a name=\"Matrix+pixelGroupKeys\"></a>\n\n### matrix.pixelGroupKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All available pixel group keys, ordered by appearance.  \n<a name=\"Matrix+pixelGroups\"></a>\n\n### matrix.pixelGroups ⇒ <code>Record.&lt;string, Array.&lt;string&gt;&gt;</code>\n**Kind**: instance property of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Record.&lt;string, Array.&lt;string&gt;&gt;</code> - Key is the group key, value is an array of pixel keys.  \n<a name=\"Matrix+_getPixelDefaultKeys\"></a>\n\n### matrix.\\_getPixelDefaultKeys() ⇒ <code>Array.&lt;Array.&lt;Array.&lt;string&gt;&gt;&gt;</code> ℗\nGenerate default keys for all pixels.\n\n**Kind**: instance method of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Array.&lt;Array.&lt;Array.&lt;string&gt;&gt;&gt;</code> - Default pixel keys by Z, Y and X position.  \n**Access**: private  \n<a name=\"Matrix+_getPixelDefaultKey\"></a>\n\n### matrix.\\_getPixelDefaultKey(x, y, z) ⇒ <code>string</code> ℗\nGenerate default name based on defined axes and given position if no custom names are set via `pixelKeys`.\n\n| Dimension | Default pixelKey |\n| --------- | ---------------- |\n| 1D        | `\"$number\"`      |\n| 2D        | `\"($x, $y)\"`     |\n| 3D        | `\"($x, $y, $z)\"` |\n\n**Kind**: instance method of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>string</code> - The pixel's default key.  \n**Throws**:\n\n- <code>RangeError</code> If [definedAxes](#Matrix+definedAxes).length is not 1, 2 or 3.\n\n**Access**: private  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| x | <code>number</code> | Position of pixel in X direction. |\n| y | <code>number</code> | Position of pixel in Y direction. |\n| z | <code>number</code> | Position of pixel in Z direction. |\n\n<a name=\"Matrix+getPixelKeysByOrder\"></a>\n\n### matrix.getPixelKeysByOrder(firstAxis, secondAxis, thirdAxis) ⇒ <code>Array.&lt;string&gt;</code>\nSorts the pixelKeys by given X/Y/Z order. Order of the parameters equals the order in a `repeatFor`'s \"eachPixelXYZ\".\n\n**Kind**: instance method of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All pixelKeys ordered by given axis order.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| firstAxis | <code>&#x27;X&#x27;</code> \\| <code>&#x27;Y&#x27;</code> \\| <code>&#x27;Z&#x27;</code> | Axis with highest ordering. |\n| secondAxis | <code>&#x27;X&#x27;</code> \\| <code>&#x27;Y&#x27;</code> \\| <code>&#x27;Z&#x27;</code> | Axis with middle ordering. |\n| thirdAxis | <code>&#x27;X&#x27;</code> \\| <code>&#x27;Y&#x27;</code> \\| <code>&#x27;Z&#x27;</code> | Axis with lowest ordering. |\n\n<a name=\"Matrix+_pixelKeyFulfillsConstraints\"></a>\n\n### matrix.\\_pixelKeyFulfillsConstraints(pixelKey, constraints) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>Matrix</code>](#Matrix)  \n**Returns**: <code>boolean</code> - True if the pixel key fulfills all constraints, false otherwise.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| pixelKey | <code>string</code> | The pixel key to check against the constraints. |\n| constraints | <code>object</code> | The constraints to apply. |\n\n<a name=\"Meta\"></a>\n\n## Meta\nInformation about a fixture's author and history.\n\n**Kind**: global class  \n\n* [Meta](#Meta)\n    * [new Meta(jsonObject)](#new_Meta_new)\n    * [.authors](#Meta+authors) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.createDate](#Meta+createDate) ⇒ <code>Date</code>\n    * [.lastModifyDate](#Meta+lastModifyDate) ⇒ <code>Date</code>\n    * [.importPlugin](#Meta+importPlugin) ⇒ <code>string</code> \\| <code>null</code>\n    * [.importDate](#Meta+importDate) ⇒ <code>Date</code> \\| <code>null</code>\n    * [.importComment](#Meta+importComment) ⇒ <code>string</code> \\| <code>null</code>\n    * [.hasImportComment](#Meta+hasImportComment) ⇒ <code>boolean</code>\n\n<a name=\"new_Meta_new\"></a>\n\n### new Meta(jsonObject)\nCreates a new Meta instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| jsonObject | <code>object</code> | A meta object from the fixture's JSON data. |\n\n<a name=\"Meta+authors\"></a>\n\n### meta.authors ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Meta</code>](#Meta)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Names of people who contributed to this fixture.  \n<a name=\"Meta+createDate\"></a>\n\n### meta.createDate ⇒ <code>Date</code>\n**Kind**: instance property of [<code>Meta</code>](#Meta)  \n**Returns**: <code>Date</code> - When this fixture was created. Might not refer to the creation in OFL, but in the lighting software from which this fixture was imported.  \n<a name=\"Meta+lastModifyDate\"></a>\n\n### meta.lastModifyDate ⇒ <code>Date</code>\n**Kind**: instance property of [<code>Meta</code>](#Meta)  \n**Returns**: <code>Date</code> - When this fixture was changed the last time. Might not refer to a modification in OFL, but in the lighting software from which this fixture was imported.  \n<a name=\"Meta+importPlugin\"></a>\n\n### meta.importPlugin ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Meta</code>](#Meta)  \n**Returns**: <code>string</code> \\| <code>null</code> - The key of the plugin with which this fixture was imported. Null if it's not imported.  \n<a name=\"Meta+importDate\"></a>\n\n### meta.importDate ⇒ <code>Date</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Meta</code>](#Meta)  \n**Returns**: <code>Date</code> \\| <code>null</code> - When this fixture was imported. Null if it's not imported.  \n<a name=\"Meta+importComment\"></a>\n\n### meta.importComment ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Meta</code>](#Meta)  \n**Returns**: <code>string</code> \\| <code>null</code> - A comment further describing the import process. Null if it's not imported.  \n<a name=\"Meta+hasImportComment\"></a>\n\n### meta.hasImportComment ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Meta</code>](#Meta)  \n**Returns**: <code>boolean</code> - Whether there is an import comment. Always false if it's not imported.  \n<a name=\"Mode\"></a>\n\n## Mode\nA fixture's configuration that enables a fixed set of channels and channel order.\n\n**Kind**: global class  \n\n* [Mode](#Mode)\n    * [new Mode(jsonObject, fixture)](#new_Mode_new)\n    * [.jsonObject](#Mode+jsonObject) ⇒ <code>object</code>\n    * [.fixture](#Mode+fixture) ⇒ [<code>Fixture</code>](#Fixture)\n    * [.name](#Mode+name) ⇒ <code>string</code>\n    * [.shortName](#Mode+shortName) ⇒ <code>string</code>\n    * [.hasShortName](#Mode+hasShortName) ⇒ <code>boolean</code>\n    * [.rdmPersonalityIndex](#Mode+rdmPersonalityIndex) ⇒ <code>number</code> \\| <code>null</code>\n    * [.physicalOverride](#Mode+physicalOverride) ⇒ [<code>Physical</code>](#Physical) \\| <code>null</code>\n    * [.physical](#Mode+physical) ⇒ [<code>Physical</code>](#Physical) \\| <code>null</code>\n    * [.channelKeys](#Mode+channelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.nullChannelCount](#Mode+nullChannelCount) ⇒ <code>number</code>\n    * [.channels](#Mode+channels) ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n    * [._getMatrixChannelKeysFromInsertBlock(channelInsert)](#Mode+_getMatrixChannelKeysFromInsertBlock) ⇒ <code>Array.&lt;string&gt;</code> ℗\n    * [._getRepeatForPixelKeys(repeatFor)](#Mode+_getRepeatForPixelKeys) ⇒ <code>Array.&lt;string&gt;</code> ℗\n    * [.getChannelIndex(channelKey, [switchingChannelBehavior])](#Mode+getChannelIndex) ⇒ <code>number</code>\n\n<a name=\"new_Mode_new\"></a>\n\n### new Mode(jsonObject, fixture)\nCreates a new Mode instance\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| jsonObject | <code>object</code> | The mode object from the fixture's JSON data. |\n| fixture | [<code>Fixture</code>](#Fixture) | The fixture this mode is associated to. |\n\n<a name=\"Mode+jsonObject\"></a>\n\n### mode.jsonObject ⇒ <code>object</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: <code>object</code> - The JSON data representing this mode. It's a fragment of a fixture's JSON data.  \n<a name=\"Mode+fixture\"></a>\n\n### mode.fixture ⇒ [<code>Fixture</code>](#Fixture)\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: [<code>Fixture</code>](#Fixture) - The fixture this mode belongs to.  \n<a name=\"Mode+name\"></a>\n\n### mode.name ⇒ <code>string</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: <code>string</code> - The mode's name from the JSON data.  \n<a name=\"Mode+shortName\"></a>\n\n### mode.shortName ⇒ <code>string</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: <code>string</code> - A shorter mode name from the JSON data. Defaults to the normal name.  \n<a name=\"Mode+hasShortName\"></a>\n\n### mode.hasShortName ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: <code>boolean</code> - Whether this mode has a short name set in the JSON data.  \n<a name=\"Mode+rdmPersonalityIndex\"></a>\n\n### mode.rdmPersonalityIndex ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: <code>number</code> \\| <code>null</code> - The index used in the RDM protocol to reference this mode. Defaults to null.  \n<a name=\"Mode+physicalOverride\"></a>\n\n### mode.physicalOverride ⇒ [<code>Physical</code>](#Physical) \\| <code>null</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: [<code>Physical</code>](#Physical) \\| <code>null</code> - Extend the fixture's physical data with this physical data object when this mode is activated. Defaults to null.  \n<a name=\"Mode+physical\"></a>\n\n### mode.physical ⇒ [<code>Physical</code>](#Physical) \\| <code>null</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: [<code>Physical</code>](#Physical) \\| <code>null</code> - Fixture's physical with mode's physical override (if present) applied on. Null if neither fixture nor mode define physical data.  \n<a name=\"Mode+channelKeys\"></a>\n\n### mode.channelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: <code>Array.&lt;string&gt;</code> - The mode's channel keys. The count and position equals to actual DMX channel count and position.  \n<a name=\"Mode+nullChannelCount\"></a>\n\n### mode.nullChannelCount ⇒ <code>number</code>\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: <code>number</code> - The number of null channels used in this mode.  \n<a name=\"Mode+channels\"></a>\n\n### mode.channels ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n**Kind**: instance property of [<code>Mode</code>](#Mode)  \n**Returns**: [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel) - The mode's channels. The count and position equals to actual DMX channel count and position.  \n<a name=\"Mode+_getMatrixChannelKeysFromInsertBlock\"></a>\n\n### mode.\\_getMatrixChannelKeysFromInsertBlock(channelInsert) ⇒ <code>Array.&lt;string&gt;</code> ℗\nResolves the matrix channel insert block into a list of channel keys\n\n**Kind**: instance method of [<code>Mode</code>](#Mode)  \n**Returns**: <code>Array.&lt;string&gt;</code> - The resolved channel keys  \n**Access**: private  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| channelInsert | <code>object</code> | The JSON channel insert block |\n\n<a name=\"Mode+_getRepeatForPixelKeys\"></a>\n\n### mode.\\_getRepeatForPixelKeys(repeatFor) ⇒ <code>Array.&lt;string&gt;</code> ℗\nResolves `repeatFor` keywords into a list of pixel (group) keys or just returns the given pixel (group) key array.\n\n**Kind**: instance method of [<code>Mode</code>](#Mode)  \n**Returns**: <code>Array.&lt;string&gt;</code> - The properly ordered list of pixel (group) keys.  \n**Access**: private  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| repeatFor | <code>string</code> \\| <code>Array.&lt;string&gt;</code> | A matrix channel insert's repeatFor property. |\n\n<a name=\"Mode+getChannelIndex\"></a>\n\n### mode.getChannelIndex(channelKey, [switchingChannelBehavior]) ⇒ <code>number</code>\n**Kind**: instance method of [<code>Mode</code>](#Mode)  \n**Returns**: <code>number</code> - The index of the given channel in this mode or -1 if not found.  \n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| channelKey | <code>string</code> |  | The key of the channel to get the index for. |\n| [switchingChannelBehavior] | [<code>SwitchingChannelBehavior</code>](#SwitchingChannelBehavior) | <code>&#x27;all&#x27;</code> | Controls how switching channels are counted, see [usesChannelKey](#SwitchingChannel+usesChannelKey) for possible values. |\n\n<a name=\"NullChannel\"></a>\n\n## NullChannel ⇐ [<code>CoarseChannel</code>](#CoarseChannel)\nDummy channel used to represent `null` in a mode's channel list.\n\n**Kind**: global class  \n**Extends**: [<code>CoarseChannel</code>](#CoarseChannel)  \n\n* [NullChannel](#NullChannel) ⇐ [<code>CoarseChannel</code>](#CoarseChannel)\n    * [new NullChannel(fixture)](#new_NullChannel_new)\n    * [.jsonObject](#CoarseChannel+jsonObject) ⇒ <code>object</code>\n    * [.fixture](#CoarseChannel+fixture) ⇒ [<code>Fixture</code>](#Fixture)\n    * [.name](#CoarseChannel+name) ⇒ <code>string</code>\n    * [.type](#CoarseChannel+type) ⇒ <code>string</code>\n    * [.color](#CoarseChannel+color) ⇒ <code>string</code> \\| <code>null</code>\n    * [.fineChannelAliases](#CoarseChannel+fineChannelAliases) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.fineChannels](#CoarseChannel+fineChannels) ⇒ [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel)\n    * [.maxResolution](#CoarseChannel+maxResolution) ⇒ [<code>Resolution</code>](#Resolution)\n    * [.dmxValueResolution](#CoarseChannel+dmxValueResolution) ⇒ [<code>Resolution</code>](#Resolution)\n    * [.maxDmxBound](#CoarseChannel+maxDmxBound) ⇒ <code>number</code>\n    * [.hasDefaultValue](#CoarseChannel+hasDefaultValue) ⇒ <code>boolean</code>\n    * [.defaultValue](#CoarseChannel+defaultValue) ⇒ <code>number</code>\n    * [._defaultValuePerResolution](#CoarseChannel+_defaultValuePerResolution) ⇒ <code>Record.&lt;Resolution, number&gt;</code> ℗\n    * [.hasHighlightValue](#CoarseChannel+hasHighlightValue) ⇒ <code>boolean</code>\n    * [.highlightValue](#CoarseChannel+highlightValue) ⇒ <code>number</code>\n    * [._highlightValuePerResolution](#CoarseChannel+_highlightValuePerResolution) ⇒ <code>Record.&lt;Resolution, number&gt;</code> ℗\n    * [.isInverted](#CoarseChannel+isInverted) ⇒ <code>boolean</code>\n    * [.isConstant](#CoarseChannel+isConstant) ⇒ <code>boolean</code>\n    * [.canCrossfade](#CoarseChannel+canCrossfade) ⇒ <code>boolean</code>\n    * [.precedence](#CoarseChannel+precedence) ⇒ <code>&#x27;HTP&#x27;</code> \\| <code>&#x27;LTP&#x27;</code>\n    * [.switchingChannelAliases](#CoarseChannel+switchingChannelAliases) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.switchingChannels](#CoarseChannel+switchingChannels) ⇒ [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel)\n    * [.switchToChannelKeys](#CoarseChannel+switchToChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.capabilities](#CoarseChannel+capabilities) ⇒ [<code>Array.&lt;Capability&gt;</code>](#Capability)\n    * [.isHelpWanted](#CoarseChannel+isHelpWanted) ⇒ <code>boolean</code>\n    * [.key](#AbstractChannel+key) ⇒ <code>string</code>\n    * [.uniqueName](#AbstractChannel+uniqueName) ⇒ <code>string</code>\n    * [.pixelKey](#AbstractChannel+pixelKey) ⇒ <code>string</code> \\| <code>null</code>\n    * [.ensureProperResolution(uncheckedResolution)](#CoarseChannel+ensureProperResolution)\n    * [.getResolutionInMode(mode, switchingChannelBehavior)](#CoarseChannel+getResolutionInMode) ⇒ [<code>Resolution</code>](#Resolution)\n    * [.getDefaultValueWithResolution(desiredResolution)](#CoarseChannel+getDefaultValueWithResolution) ⇒ <code>number</code>\n    * [.getHighlightValueWithResolution(desiredResolution)](#CoarseChannel+getHighlightValueWithResolution) ⇒ <code>number</code>\n\n<a name=\"new_NullChannel_new\"></a>\n\n### new NullChannel(fixture)\nCreates a new NullChannel instance by creating a Channel object with NoFunction channel data.\nUses a unique uuid as channel key.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| fixture | [<code>Fixture</code>](#Fixture) | The fixture this channel is associated to. |\n\n<a name=\"CoarseChannel+jsonObject\"></a>\n\n### nullChannel.jsonObject ⇒ <code>object</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>jsonObject</code>](#CoarseChannel+jsonObject)  \n**Returns**: <code>object</code> - The channel data from the fixture's JSON.  \n<a name=\"CoarseChannel+fixture\"></a>\n\n### nullChannel.fixture ⇒ [<code>Fixture</code>](#Fixture)\nOverrides [`AbstractChannel.fixture`](#AbstractChannel+fixture).\n\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>fixture</code>](#CoarseChannel+fixture)  \n**Returns**: [<code>Fixture</code>](#Fixture) - The fixture instance this channel is associated to.  \n<a name=\"CoarseChannel+name\"></a>\n\n### nullChannel.name ⇒ <code>string</code>\nOverrides [`AbstractChannel.name`](#AbstractChannel+name).\n\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>name</code>](#CoarseChannel+name)  \n**Returns**: <code>string</code> - The channel name if present or else the channel key.  \n<a name=\"CoarseChannel+type\"></a>\n\n### nullChannel.type ⇒ <code>string</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>type</code>](#CoarseChannel+type)  \n**Returns**: <code>string</code> - The channel type, derived from the channel's capability types.  \n<a name=\"CoarseChannel+color\"></a>\n\n### nullChannel.color ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>color</code>](#CoarseChannel+color)  \n**Returns**: <code>string</code> \\| <code>null</code> - The color of an included ColorIntensity capability, null if there's no such capability.  \n<a name=\"CoarseChannel+fineChannelAliases\"></a>\n\n### nullChannel.fineChannelAliases ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>fineChannelAliases</code>](#CoarseChannel+fineChannelAliases)  \n**Returns**: <code>Array.&lt;string&gt;</code> - This channel's fine channel aliases, ordered by resolution (coarsest first).  \n<a name=\"CoarseChannel+fineChannels\"></a>\n\n### nullChannel.fineChannels ⇒ [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel)\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>fineChannels</code>](#CoarseChannel+fineChannels)  \n**Returns**: [<code>Array.&lt;FineChannel&gt;</code>](#FineChannel) - This channel's fine channels, ordered by resolution (coarsest first).  \n<a name=\"CoarseChannel+maxResolution\"></a>\n\n### nullChannel.maxResolution ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>maxResolution</code>](#CoarseChannel+maxResolution)  \n**Returns**: [<code>Resolution</code>](#Resolution) - How fine this channel can be used at its maximum. Equals the amount of coarse and fine channels.  \n<a name=\"CoarseChannel+dmxValueResolution\"></a>\n\n### nullChannel.dmxValueResolution ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>dmxValueResolution</code>](#CoarseChannel+dmxValueResolution)  \n**Returns**: [<code>Resolution</code>](#Resolution) - How fine this channel is declared in the JSON data. Defaults to [maxResolution](#CoarseChannel+maxResolution).  \n<a name=\"CoarseChannel+maxDmxBound\"></a>\n\n### nullChannel.maxDmxBound ⇒ <code>number</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>maxDmxBound</code>](#CoarseChannel+maxDmxBound)  \n**Returns**: <code>number</code> - The maximum DMX value in the highest possible resolution. E.g. 65535 for a 16bit channel.  \n<a name=\"CoarseChannel+hasDefaultValue\"></a>\n\n### nullChannel.hasDefaultValue ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>hasDefaultValue</code>](#CoarseChannel+hasDefaultValue)  \n**Returns**: <code>boolean</code> - Whether this channel has a defaultValue.  \n<a name=\"CoarseChannel+defaultValue\"></a>\n\n### nullChannel.defaultValue ⇒ <code>number</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>defaultValue</code>](#CoarseChannel+defaultValue)  \n**Returns**: <code>number</code> - The DMX value this channel initially should be set to. Specified in the finest possible resolution. Defaults to 0.  \n<a name=\"CoarseChannel+_defaultValuePerResolution\"></a>\n\n### nullChannel.\\_defaultValuePerResolution ⇒ <code>Record.&lt;Resolution, number&gt;</code> ℗\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>\\_defaultValuePerResolution</code>](#CoarseChannel+_defaultValuePerResolution)  \n**Returns**: <code>Record.&lt;Resolution, number&gt;</code> - The default DMX value of this channel in the given resolution, for all resolutions up to the channel's maximum resolution.  \n**Access**: private  \n<a name=\"CoarseChannel+hasHighlightValue\"></a>\n\n### nullChannel.hasHighlightValue ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>hasHighlightValue</code>](#CoarseChannel+hasHighlightValue)  \n**Returns**: <code>boolean</code> - Whether this channel has a highlightValue.  \n<a name=\"CoarseChannel+highlightValue\"></a>\n\n### nullChannel.highlightValue ⇒ <code>number</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>highlightValue</code>](#CoarseChannel+highlightValue)  \n**Returns**: <code>number</code> - A DMX value that \"highlights\" the function of this channel. Specified in the finest possible resolution. Defaults to the highest possible DMX value.  \n<a name=\"CoarseChannel+_highlightValuePerResolution\"></a>\n\n### nullChannel.\\_highlightValuePerResolution ⇒ <code>Record.&lt;Resolution, number&gt;</code> ℗\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>\\_highlightValuePerResolution</code>](#CoarseChannel+_highlightValuePerResolution)  \n**Returns**: <code>Record.&lt;Resolution, number&gt;</code> - The highlight DMX value of this channel in the given resolution, for all resolutions up to the channel's maximum resolution.  \n**Access**: private  \n<a name=\"CoarseChannel+isInverted\"></a>\n\n### nullChannel.isInverted ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>isInverted</code>](#CoarseChannel+isInverted)  \n**Returns**: <code>boolean</code> - Whether a fader for this channel should be displayed upside down.  \n<a name=\"CoarseChannel+isConstant\"></a>\n\n### nullChannel.isConstant ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>isConstant</code>](#CoarseChannel+isConstant)  \n**Returns**: <code>boolean</code> - Whether this channel should constantly stay at the same value.  \n<a name=\"CoarseChannel+canCrossfade\"></a>\n\n### nullChannel.canCrossfade ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>canCrossfade</code>](#CoarseChannel+canCrossfade)  \n**Returns**: <code>boolean</code> - Whether switching from one DMX value to another in this channel can be faded smoothly.  \n<a name=\"CoarseChannel+precedence\"></a>\n\n### nullChannel.precedence ⇒ <code>&#x27;HTP&#x27;</code> \\| <code>&#x27;LTP&#x27;</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>precedence</code>](#CoarseChannel+precedence)  \n**Returns**: <code>&#x27;HTP&#x27;</code> \\| <code>&#x27;LTP&#x27;</code> - The channel's behavior when being affected by multiple faders: HTP (Highest Takes Precedent) or LTP (Latest Takes Precedent).  \n<a name=\"CoarseChannel+switchingChannelAliases\"></a>\n\n### nullChannel.switchingChannelAliases ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>switchingChannelAliases</code>](#CoarseChannel+switchingChannelAliases)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Aliases of the switching channels defined by this channel, ordered by appearance in the JSON.  \n<a name=\"CoarseChannel+switchingChannels\"></a>\n\n### nullChannel.switchingChannels ⇒ [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel)\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>switchingChannels</code>](#CoarseChannel+switchingChannels)  \n**Returns**: [<code>Array.&lt;SwitchingChannel&gt;</code>](#SwitchingChannel) - Switching channels defined by this channel, ordered by appearance in the JSON.  \n<a name=\"CoarseChannel+switchToChannelKeys\"></a>\n\n### nullChannel.switchToChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>switchToChannelKeys</code>](#CoarseChannel+switchToChannelKeys)  \n**Returns**: <code>Array.&lt;string&gt;</code> - The keys of the channels to which the switching channels defined by this channel can be switched to.  \n<a name=\"CoarseChannel+capabilities\"></a>\n\n### nullChannel.capabilities ⇒ [<code>Array.&lt;Capability&gt;</code>](#Capability)\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>capabilities</code>](#CoarseChannel+capabilities)  \n**Returns**: [<code>Array.&lt;Capability&gt;</code>](#Capability) - All capabilities of this channel, ordered by DMX range.  \n<a name=\"CoarseChannel+isHelpWanted\"></a>\n\n### nullChannel.isHelpWanted ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>isHelpWanted</code>](#CoarseChannel+isHelpWanted)  \n**Returns**: <code>boolean</code> - True if help is needed in a capability of this channel, false otherwise.  \n<a name=\"AbstractChannel+key\"></a>\n\n### nullChannel.key ⇒ <code>string</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>key</code>](#AbstractChannel+key)  \n**Returns**: <code>string</code> - The channel key.  \n<a name=\"AbstractChannel+uniqueName\"></a>\n\n### nullChannel.uniqueName ⇒ <code>string</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>uniqueName</code>](#AbstractChannel+uniqueName)  \n**Returns**: <code>string</code> - Unique version of this channel's name.  \n**See**: [uniqueChannelNames](#Fixture+uniqueChannelNames)  \n<a name=\"AbstractChannel+pixelKey\"></a>\n\n### nullChannel.pixelKey ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>pixelKey</code>](#AbstractChannel+pixelKey)  \n**Returns**: <code>string</code> \\| <code>null</code> - The key of the pixel (group) that this channel is associated to. Defaults to null.  \n<a name=\"CoarseChannel+ensureProperResolution\"></a>\n\n### nullChannel.ensureProperResolution(uncheckedResolution)\nChecks the given resolution if it can safely be used in this channel.\n\n**Kind**: instance method of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>ensureProperResolution</code>](#CoarseChannel+ensureProperResolution)  \n**Throws**:\n\n- <code>RangeError</code> If the given resolution is invalid in this channel.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| uncheckedResolution | [<code>Resolution</code>](#Resolution) | The resolution to be checked. |\n\n<a name=\"CoarseChannel+getResolutionInMode\"></a>\n\n### nullChannel.getResolutionInMode(mode, switchingChannelBehavior) ⇒ [<code>Resolution</code>](#Resolution)\n**Kind**: instance method of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>getResolutionInMode</code>](#CoarseChannel+getResolutionInMode)  \n**Returns**: [<code>Resolution</code>](#Resolution) - How fine this channel is used in the given mode. 0 if the channel isn't used at all.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| mode | [<code>Mode</code>](#Mode) | The mode in which this channel is used. |\n| switchingChannelBehavior | [<code>SwitchingChannelBehavior</code>](#SwitchingChannelBehavior) | How switching channels are treated, see [getChannelIndex](#Mode+getChannelIndex). |\n\n<a name=\"CoarseChannel+getDefaultValueWithResolution\"></a>\n\n### nullChannel.getDefaultValueWithResolution(desiredResolution) ⇒ <code>number</code>\n**Kind**: instance method of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>getDefaultValueWithResolution</code>](#CoarseChannel+getDefaultValueWithResolution)  \n**Returns**: <code>number</code> - The DMX value this channel initially should be set to, scaled to match the given resolution.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| desiredResolution | [<code>Resolution</code>](#Resolution) | The grade of resolution the defaultValue should be scaled to. |\n\n<a name=\"CoarseChannel+getHighlightValueWithResolution\"></a>\n\n### nullChannel.getHighlightValueWithResolution(desiredResolution) ⇒ <code>number</code>\n**Kind**: instance method of [<code>NullChannel</code>](#NullChannel)  \n**Overrides**: [<code>getHighlightValueWithResolution</code>](#CoarseChannel+getHighlightValueWithResolution)  \n**Returns**: <code>number</code> - A DMX value that \"highlights\" the function of this channel, scaled to match the given resolution.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| desiredResolution | [<code>Resolution</code>](#Resolution) | The grade of resolution the highlightValue should be scaled to. |\n\n<a name=\"Physical\"></a>\n\n## Physical\nA fixture's technical data, belonging to the hardware and not the DMX protocol.\n\n**Kind**: global class  \n\n* [Physical](#Physical)\n    * [new Physical(jsonObject)](#new_Physical_new)\n    * [.jsonObject](#Physical+jsonObject) ⇒ <code>object</code>\n    * [.dimensions](#Physical+dimensions) ⇒ <code>Array.&lt;number&gt;</code> \\| <code>null</code>\n    * [.width](#Physical+width) ⇒ <code>number</code> \\| <code>null</code>\n    * [.height](#Physical+height) ⇒ <code>number</code> \\| <code>null</code>\n    * [.depth](#Physical+depth) ⇒ <code>number</code> \\| <code>null</code>\n    * [.weight](#Physical+weight) ⇒ <code>number</code> \\| <code>null</code>\n    * [.power](#Physical+power) ⇒ <code>number</code> \\| <code>null</code>\n    * [.powerConnectors](#Physical+powerConnectors) ⇒ <code>Record.&lt;string, string&gt;</code>\n    * [.DMXconnector](#Physical+DMXconnector) ⇒ <code>string</code> \\| <code>null</code>\n    * [.hasBulb](#Physical+hasBulb) ⇒ <code>boolean</code>\n    * [.bulbType](#Physical+bulbType) ⇒ <code>string</code> \\| <code>null</code>\n    * [.bulbColorTemperature](#Physical+bulbColorTemperature) ⇒ <code>number</code> \\| <code>null</code>\n    * [.bulbLumens](#Physical+bulbLumens) ⇒ <code>number</code> \\| <code>null</code>\n    * [.hasLens](#Physical+hasLens) ⇒ <code>boolean</code>\n    * [.lensName](#Physical+lensName) ⇒ <code>string</code> \\| <code>null</code>\n    * [.lensDegreesMin](#Physical+lensDegreesMin) ⇒ <code>number</code> \\| <code>null</code>\n    * [.lensDegreesMax](#Physical+lensDegreesMax) ⇒ <code>number</code> \\| <code>null</code>\n    * [.hasMatrixPixels](#Physical+hasMatrixPixels) ⇒ <code>boolean</code>\n    * [.matrixPixelsDimensions](#Physical+matrixPixelsDimensions) ⇒ <code>Array.&lt;number&gt;</code> \\| <code>null</code>\n    * [.matrixPixelsSpacing](#Physical+matrixPixelsSpacing) ⇒ <code>Array.&lt;number&gt;</code> \\| <code>null</code>\n\n<a name=\"new_Physical_new\"></a>\n\n### new Physical(jsonObject)\nCreates a new Physical instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| jsonObject | <code>object</code> | A fixture's or mode's physical JSON data. |\n\n<a name=\"Physical+jsonObject\"></a>\n\n### physical.jsonObject ⇒ <code>object</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>object</code> - The object from the JSON data that is represented by this Physical object.  \n<a name=\"Physical+dimensions\"></a>\n\n### physical.dimensions ⇒ <code>Array.&lt;number&gt;</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>Array.&lt;number&gt;</code> \\| <code>null</code> - Width, height and depth of the fixture in millimeters. Defaults to null.  \n<a name=\"Physical+width\"></a>\n\n### physical.width ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - Width of the fixture in millimeters. Defaults to null.  \n<a name=\"Physical+height\"></a>\n\n### physical.height ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - Height of the fixture in millimeters. Defaults to null.  \n<a name=\"Physical+depth\"></a>\n\n### physical.depth ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - Depth of the fixture in millimeters. Defaults to null.  \n<a name=\"Physical+weight\"></a>\n\n### physical.weight ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - Weight of the fixture in kilograms. Defaults to null.  \n<a name=\"Physical+power\"></a>\n\n### physical.power ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - Power consumption of the fixture in watts. Defaults to null.  \n<a name=\"Physical+powerConnectors\"></a>\n\n### physical.powerConnectors ⇒ <code>Record.&lt;string, string&gt;</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>Record.&lt;string, string&gt;</code> - Power connector information.  \n<a name=\"Physical+DMXconnector\"></a>\n\n### physical.DMXconnector ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>string</code> \\| <code>null</code> - The DMX plug to be used to control the fixture, e.g. \"3-pin\" (XLR). Defaults to null.  \n<a name=\"Physical+hasBulb\"></a>\n\n### physical.hasBulb ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>boolean</code> - Whether physical data about the light source is available.  \n<a name=\"Physical+bulbType\"></a>\n\n### physical.bulbType ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>string</code> \\| <code>null</code> - The kind of lamp that is used in the fixture, e.g. \"LED\". Defaults to null.  \n<a name=\"Physical+bulbColorTemperature\"></a>\n\n### physical.bulbColorTemperature ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - The color temperature of the bulb in kelvins. Defaults to null.  \n<a name=\"Physical+bulbLumens\"></a>\n\n### physical.bulbLumens ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - The luminous flux of the bulb in lumens. Defaults to null.  \n<a name=\"Physical+hasLens\"></a>\n\n### physical.hasLens ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>boolean</code> - Whether physical data about the lens is available.  \n<a name=\"Physical+lensName\"></a>\n\n### physical.lensName ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>string</code> \\| <code>null</code> - The kind of lens that is used in the fixture, e.g. \"Fresnel\". Defaults to null.  \n<a name=\"Physical+lensDegreesMin\"></a>\n\n### physical.lensDegreesMin ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - The minimum possible beam angle in degrees. Defaults to null.  \n<a name=\"Physical+lensDegreesMax\"></a>\n\n### physical.lensDegreesMax ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>number</code> \\| <code>null</code> - The maximum possible beam angle in degrees. Defaults to null.  \n<a name=\"Physical+hasMatrixPixels\"></a>\n\n### physical.hasMatrixPixels ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>boolean</code> - Whether physical data about the matrix is available.  \n<a name=\"Physical+matrixPixelsDimensions\"></a>\n\n### physical.matrixPixelsDimensions ⇒ <code>Array.&lt;number&gt;</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>Array.&lt;number&gt;</code> \\| <code>null</code> - Width, height, depth of a matrix pixel in millimeters.  \n<a name=\"Physical+matrixPixelsSpacing\"></a>\n\n### physical.matrixPixelsSpacing ⇒ <code>Array.&lt;number&gt;</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Physical</code>](#Physical)  \n**Returns**: <code>Array.&lt;number&gt;</code> \\| <code>null</code> - XYZ-Spacing between matrix pixels in millimeters.  \n<a name=\"Range\"></a>\n\n## Range\nRepresents a range from one integer to a higher or equal integer. Primarily used for DMX ranges of capabilities.\n\n**Kind**: global class  \n\n* [Range](#Range)\n    * [new Range(rangeArray)](#new_Range_new)\n    * _instance_\n        * [.start](#Range+start) ⇒ <code>number</code>\n        * [.end](#Range+end) ⇒ <code>number</code>\n        * [.center](#Range+center) ⇒ <code>number</code>\n        * [.contains(value)](#Range+contains) ⇒ <code>boolean</code>\n        * [.overlapsWith(range)](#Range+overlapsWith) ⇒ <code>boolean</code>\n        * [.overlapsWithOneOf(ranges)](#Range+overlapsWithOneOf) ⇒ <code>boolean</code>\n        * [.isAdjacentTo(range)](#Range+isAdjacentTo) ⇒ <code>boolean</code>\n        * [.getRangeMergedWith(range)](#Range+getRangeMergedWith) ⇒ [<code>Range</code>](#Range)\n        * [.toString()](#Range+toString) ⇒ <code>string</code>\n    * _static_\n        * [.getMergedRanges(ranges)](#Range.getMergedRanges) ⇒ [<code>Array.&lt;Range&gt;</code>](#Range)\n\n<a name=\"new_Range_new\"></a>\n\n### new Range(rangeArray)\nCreates a new Range instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| rangeArray | <code>Array.&lt;number&gt;</code> | Array of start and end value. Start value may not be greater than end value. |\n\n<a name=\"Range+start\"></a>\n\n### range.start ⇒ <code>number</code>\n**Kind**: instance property of [<code>Range</code>](#Range)  \n**Returns**: <code>number</code> - The start number of the range. Lower or equal to end.  \n<a name=\"Range+end\"></a>\n\n### range.end ⇒ <code>number</code>\n**Kind**: instance property of [<code>Range</code>](#Range)  \n**Returns**: <code>number</code> - The end number of the range. Higher or equal to start.  \n<a name=\"Range+center\"></a>\n\n### range.center ⇒ <code>number</code>\n**Kind**: instance property of [<code>Range</code>](#Range)  \n**Returns**: <code>number</code> - The arithmetic mean of start and end value. Can be a fraction.  \n<a name=\"Range+contains\"></a>\n\n### range.contains(value) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>Range</code>](#Range)  \n**Returns**: <code>boolean</code> - Whether the given number is inside this range, i.e. if it's not lower than the start value and not higher than the end value.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| value | <code>number</code> | The number to check whether it's in the range. |\n\n<a name=\"Range+overlapsWith\"></a>\n\n### range.overlapsWith(range) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>Range</code>](#Range)  \n**Returns**: <code>boolean</code> - Whether this range overlaps with the given one.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| range | [<code>Range</code>](#Range) | Another Range object. |\n\n<a name=\"Range+overlapsWithOneOf\"></a>\n\n### range.overlapsWithOneOf(ranges) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>Range</code>](#Range)  \n**Returns**: <code>boolean</code> - Whether this range overlaps with any of the given ones.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| ranges | [<code>Array.&lt;Range&gt;</code>](#Range) | An array of Range objects. |\n\n<a name=\"Range+isAdjacentTo\"></a>\n\n### range.isAdjacentTo(range) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>Range</code>](#Range)  \n**Returns**: <code>boolean</code> - Whether this range is exactly next to the given one, i.e. the lower range's end value is by 1 lower than the higher range's start value.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| range | [<code>Range</code>](#Range) | Another Range object. |\n\n<a name=\"Range+getRangeMergedWith\"></a>\n\n### range.getRangeMergedWith(range) ⇒ [<code>Range</code>](#Range)\n**Kind**: instance method of [<code>Range</code>](#Range)  \n**Returns**: [<code>Range</code>](#Range) - A new range that covers both the initial and the other range.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| range | [<code>Range</code>](#Range) | Another range to merge with. |\n\n<a name=\"Range+toString\"></a>\n\n### range.toString() ⇒ <code>string</code>\n**Kind**: instance method of [<code>Range</code>](#Range)  \n**Returns**: <code>string</code> - Textual representation of this range.  \n<a name=\"Range.getMergedRanges\"></a>\n\n### Range.getMergedRanges(ranges) ⇒ [<code>Array.&lt;Range&gt;</code>](#Range)\nMerge specified Range objects. Asserts that ranges don't overlap and that all ranges are valid (start<=end).\n\n**Kind**: static method of [<code>Range</code>](#Range)  \n**Returns**: [<code>Array.&lt;Range&gt;</code>](#Range) - Merged ranges.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| ranges | [<code>Array.&lt;Range&gt;</code>](#Range) | Range objects to merge into as few ranges as possible. |\n\n<a name=\"Resource\"></a>\n\n## Resource\nInformation about a resource.\n\n**Kind**: global class  \n\n* [Resource](#Resource)\n    * [new Resource(jsonObject)](#new_Resource_new)\n    * [.name](#Resource+name) ⇒ <code>string</code>\n    * [.keywords](#Resource+keywords) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.source](#Resource+source) ⇒ <code>string</code> \\| <code>null</code>\n    * [.key](#Resource+key) ⇒ <code>string</code>\n    * [.type](#Resource+type) ⇒ <code>string</code>\n    * [.alias](#Resource+alias) ⇒ <code>string</code> \\| <code>null</code>\n    * [.hasImage](#Resource+hasImage) ⇒ <code>boolean</code>\n    * [.imageExtension](#Resource+imageExtension) ⇒ <code>string</code> \\| <code>null</code>\n    * [.imageMimeType](#Resource+imageMimeType) ⇒ <code>string</code> \\| <code>null</code>\n    * [.imageData](#Resource+imageData) ⇒ <code>string</code> \\| <code>null</code>\n    * [.imageEncoding](#Resource+imageEncoding) ⇒ <code>&#x27;base64&#x27;</code> \\| <code>&#x27;utf-8&#x27;</code> \\| <code>null</code>\n    * [.imageDataUrl](#Resource+imageDataUrl) ⇒ <code>string</code> \\| <code>null</code>\n\n<a name=\"new_Resource_new\"></a>\n\n### new Resource(jsonObject)\nCreates a new Resource instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| jsonObject | <code>object</code> | An embedded resource object from the fixture's JSON data. |\n\n<a name=\"Resource+name\"></a>\n\n### resource.name ⇒ <code>string</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> - The resource's name.  \n<a name=\"Resource+keywords\"></a>\n\n### resource.keywords ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>Array.&lt;string&gt;</code> - An array of keywords belonging to this resource.  \n<a name=\"Resource+source\"></a>\n\n### resource.source ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> \\| <code>null</code> - The source this resource was taken from, or null if it's not specified.  \n<a name=\"Resource+key\"></a>\n\n### resource.key ⇒ <code>string</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> - The resource key.  \n<a name=\"Resource+type\"></a>\n\n### resource.type ⇒ <code>string</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> - The resource name, i.e. its directory.  \n<a name=\"Resource+alias\"></a>\n\n### resource.alias ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> \\| <code>null</code> - The resource alias, as specified in the fixture, or null if the resource was referenced directly.  \n<a name=\"Resource+hasImage\"></a>\n\n### resource.hasImage ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>boolean</code> - True if this resource has an associated image, false otherwise.  \n<a name=\"Resource+imageExtension\"></a>\n\n### resource.imageExtension ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> \\| <code>null</code> - The resource image's file extension, or null if there is no image.  \n<a name=\"Resource+imageMimeType\"></a>\n\n### resource.imageMimeType ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> \\| <code>null</code> - The resource image's MIME type, or null if there is no image.  \n<a name=\"Resource+imageData\"></a>\n\n### resource.imageData ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> \\| <code>null</code> - The resource image data (base64 or utf-8 encoded), or null if there is no image.  \n<a name=\"Resource+imageEncoding\"></a>\n\n### resource.imageEncoding ⇒ <code>&#x27;base64&#x27;</code> \\| <code>&#x27;utf-8&#x27;</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>&#x27;base64&#x27;</code> \\| <code>&#x27;utf-8&#x27;</code> \\| <code>null</code> - The resource image's data encoding, or null if there is no image.  \n<a name=\"Resource+imageDataUrl\"></a>\n\n### resource.imageDataUrl ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>Resource</code>](#Resource)  \n**Returns**: <code>string</code> \\| <code>null</code> - A data URL containing the resource image, or null if there is no image.  \n<a name=\"SwitchingChannel\"></a>\n\n## SwitchingChannel ⇐ [<code>AbstractChannel</code>](#AbstractChannel)\nRepresents a channel that switches its behavior depending on trigger channel's value.\nThe different behaviors are implemented as different [CoarseChannel](#CoarseChannel)s or [FineChannel](#FineChannel)s.\n\n**Kind**: global class  \n**Extends**: [<code>AbstractChannel</code>](#AbstractChannel)  \n\n* [SwitchingChannel](#SwitchingChannel) ⇐ [<code>AbstractChannel</code>](#AbstractChannel)\n    * [new SwitchingChannel(alias, triggerChannel)](#new_SwitchingChannel_new)\n    * [.triggerChannel](#SwitchingChannel+triggerChannel) ⇒ [<code>AbstractChannel</code>](#AbstractChannel)\n    * [.fixture](#SwitchingChannel+fixture) ⇒ [<code>Fixture</code>](#Fixture)\n    * [.triggerCapabilities](#SwitchingChannel+triggerCapabilities) ⇒ [<code>Array.&lt;TriggerCapability&gt;</code>](#TriggerCapability)\n    * [.triggerRanges](#SwitchingChannel+triggerRanges) ⇒ <code>Record.&lt;string, Array.&lt;Range&gt;&gt;</code>\n    * [.defaultChannelKey](#SwitchingChannel+defaultChannelKey) ⇒ <code>string</code>\n    * [.defaultChannel](#SwitchingChannel+defaultChannel) ⇒ [<code>AbstractChannel</code>](#AbstractChannel)\n    * [.switchToChannelKeys](#SwitchingChannel+switchToChannelKeys) ⇒ <code>Array.&lt;string&gt;</code>\n    * [.switchToChannels](#SwitchingChannel+switchToChannels) ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n    * [.isHelpWanted](#SwitchingChannel+isHelpWanted) ⇒ <code>boolean</code>\n    * [.key](#AbstractChannel+key) ⇒ <code>string</code>\n    * [.name](#AbstractChannel+name) ⇒ <code>string</code>\n    * [.uniqueName](#AbstractChannel+uniqueName) ⇒ <code>string</code>\n    * [.pixelKey](#AbstractChannel+pixelKey) ⇒ <code>string</code> \\| <code>null</code>\n    * [.usesChannelKey(channelKey, [switchingChannelBehavior])](#SwitchingChannel+usesChannelKey) ⇒ <code>boolean</code>\n\n<a name=\"new_SwitchingChannel_new\"></a>\n\n### new SwitchingChannel(alias, triggerChannel)\nCreates a new SwitchingChannel instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| alias | <code>string</code> | The unique switching channel alias as defined in the trigger channel's `switchChannels` properties. |\n| triggerChannel | [<code>AbstractChannel</code>](#AbstractChannel) | The channel whose DMX value this channel depends on. |\n\n<a name=\"SwitchingChannel+triggerChannel\"></a>\n\n### switchingChannel.triggerChannel ⇒ [<code>AbstractChannel</code>](#AbstractChannel)\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: [<code>AbstractChannel</code>](#AbstractChannel) - The channel whose DMX value this switching channel depends on.  \n<a name=\"SwitchingChannel+fixture\"></a>\n\n### switchingChannel.fixture ⇒ [<code>Fixture</code>](#Fixture)\nOverrides [`AbstractChannel.fixture`](#AbstractChannel+fixture).\n\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Overrides**: [<code>fixture</code>](#AbstractChannel+fixture)  \n**Returns**: [<code>Fixture</code>](#Fixture) - The fixture in which this channel is used.  \n<a name=\"SwitchingChannel+triggerCapabilities\"></a>\n\n### switchingChannel.triggerCapabilities ⇒ [<code>Array.&lt;TriggerCapability&gt;</code>](#TriggerCapability)\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: [<code>Array.&lt;TriggerCapability&gt;</code>](#TriggerCapability) - The trigger channel's capabilities in a compact form to only include the DMX range and which channel should be switched to. DMX values are given in the trigger channel's highest possible resolution.  \n<a name=\"SwitchingChannel+triggerRanges\"></a>\n\n### switchingChannel.triggerRanges ⇒ <code>Record.&lt;string, Array.&lt;Range&gt;&gt;</code>\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: <code>Record.&lt;string, Array.&lt;Range&gt;&gt;</code> - Keys of channels that can be switched to pointing to an array of DMX values the trigger channel must be set to to active the channel. DMX values are given in the trigger channel's highest possible resolution.  \n<a name=\"SwitchingChannel+defaultChannelKey\"></a>\n\n### switchingChannel.defaultChannelKey ⇒ <code>string</code>\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: <code>string</code> - The key of the channel that is activated when the trigger channel is set to its default value.  \n<a name=\"SwitchingChannel+defaultChannel\"></a>\n\n### switchingChannel.defaultChannel ⇒ [<code>AbstractChannel</code>](#AbstractChannel)\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: [<code>AbstractChannel</code>](#AbstractChannel) - The channel that is activated when the trigger channel is set to its default value.  \n<a name=\"SwitchingChannel+switchToChannelKeys\"></a>\n\n### switchingChannel.switchToChannelKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: <code>Array.&lt;string&gt;</code> - All channel keys this channel can be switched to.  \n<a name=\"SwitchingChannel+switchToChannels\"></a>\n\n### switchingChannel.switchToChannels ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel) - All channels this channel can be switched to.  \n<a name=\"SwitchingChannel+isHelpWanted\"></a>\n\n### switchingChannel.isHelpWanted ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: <code>boolean</code> - True if help is needed in one of the switched channels, false otherwise.  \n<a name=\"AbstractChannel+key\"></a>\n\n### switchingChannel.key ⇒ <code>string</code>\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Overrides**: [<code>key</code>](#AbstractChannel+key)  \n**Returns**: <code>string</code> - The channel key.  \n<a name=\"AbstractChannel+name\"></a>\n\n### switchingChannel.name ⇒ <code>string</code>\nOverride this method for more sensible implementation.\n\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Overrides**: [<code>name</code>](#AbstractChannel+name)  \n**Returns**: <code>string</code> - The channel key (as name).  \n<a name=\"AbstractChannel+uniqueName\"></a>\n\n### switchingChannel.uniqueName ⇒ <code>string</code>\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Overrides**: [<code>uniqueName</code>](#AbstractChannel+uniqueName)  \n**Returns**: <code>string</code> - Unique version of this channel's name.  \n**See**: [uniqueChannelNames](#Fixture+uniqueChannelNames)  \n<a name=\"AbstractChannel+pixelKey\"></a>\n\n### switchingChannel.pixelKey ⇒ <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Overrides**: [<code>pixelKey</code>](#AbstractChannel+pixelKey)  \n**Returns**: <code>string</code> \\| <code>null</code> - The key of the pixel (group) that this channel is associated to. Defaults to null.  \n<a name=\"SwitchingChannel+usesChannelKey\"></a>\n\n### switchingChannel.usesChannelKey(channelKey, [switchingChannelBehavior]) ⇒ <code>boolean</code>\n**Kind**: instance method of [<code>SwitchingChannel</code>](#SwitchingChannel)  \n**Returns**: <code>boolean</code> - Whether this SwitchingChannel contains the given channel key.  \n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| channelKey | <code>string</code> |  | The channel key to search for. |\n| [switchingChannelBehavior] | [<code>SwitchingChannelBehavior</code>](#SwitchingChannelBehavior) | <code>&#x27;all&#x27;</code> | Define which channels to include in the search. |\n\n<a name=\"TemplateChannel\"></a>\n\n## TemplateChannel\nRepresents a blueprint channel of which several similar channels can be generated.\nCurrently used to create matrix channels.\n\n**Kind**: global class  \n\n* [TemplateChannel](#TemplateChannel)\n    * [new TemplateChannel(key, jsonObject, fixture)](#new_TemplateChannel_new)\n    * _instance_\n        * [.allTemplateKeys](#TemplateChannel+allTemplateKeys) ⇒ <code>Array.&lt;string&gt;</code>\n        * [.possibleMatrixChannelKeys](#TemplateChannel+possibleMatrixChannelKeys) ⇒ <code>Map.&lt;string, Array.&lt;string&gt;&gt;</code>\n        * [.createMatrixChannels()](#TemplateChannel+createMatrixChannels) ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\n    * _static_\n        * [.resolveTemplateObject(object, variables)](#TemplateChannel.resolveTemplateObject) ⇒ <code>object</code>\n        * [.resolveTemplateString(string, variables)](#TemplateChannel.resolveTemplateString) ⇒ <code>string</code>\n\n<a name=\"new_TemplateChannel_new\"></a>\n\n### new TemplateChannel(key, jsonObject, fixture)\nCreates new TemplateChannel instance. Also clears cache by setting jsonObject.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| key | <code>string</code> | The templateChannel's key with the required variables. |\n| jsonObject | <code>object</code> | The template's JSON data which looks pretty similar to a normal channel's data except that channel aliases must include variables. |\n| fixture | [<code>Fixture</code>](#Fixture) | The Fixture instance. |\n\n<a name=\"TemplateChannel+allTemplateKeys\"></a>\n\n### templateChannel.allTemplateKeys ⇒ <code>Array.&lt;string&gt;</code>\n**Kind**: instance property of [<code>TemplateChannel</code>](#TemplateChannel)  \n**Returns**: <code>Array.&lt;string&gt;</code> - Template keys and aliases introduced by this channel, i.e. the channel key itself and defined fine and switching channels.  \n<a name=\"TemplateChannel+possibleMatrixChannelKeys\"></a>\n\n### templateChannel.possibleMatrixChannelKeys ⇒ <code>Map.&lt;string, Array.&lt;string&gt;&gt;</code>\n**Kind**: instance property of [<code>TemplateChannel</code>](#TemplateChannel)  \n**Returns**: <code>Map.&lt;string, Array.&lt;string&gt;&gt;</code> - All template keys pointing to the key resolved with each pixel key to a matrix channel key.  \n<a name=\"TemplateChannel+createMatrixChannels\"></a>\n\n### templateChannel.createMatrixChannels() ⇒ [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel)\nCreates matrix channels from this template channel (together with its fine and switching channels if defined) and all pixel keys.\n\n**Kind**: instance method of [<code>TemplateChannel</code>](#TemplateChannel)  \n**Returns**: [<code>Array.&lt;AbstractChannel&gt;</code>](#AbstractChannel) - The generated channels associated to the given pixel key and its fine and switching channels.  \n<a name=\"TemplateChannel.resolveTemplateObject\"></a>\n\n### TemplateChannel.resolveTemplateObject(object, variables) ⇒ <code>object</code>\nReplaces the specified variables in the specified object by cloning the object.\n\n**Kind**: static method of [<code>TemplateChannel</code>](#TemplateChannel)  \n**Returns**: <code>object</code> - A copy of the object with replaced variables.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| object | <code>object</code> | The object which has to be modified. |\n| variables | <code>Record.&lt;string, string&gt;</code> | Each variable (without $) pointing to its value. |\n\n<a name=\"TemplateChannel.resolveTemplateString\"></a>\n\n### TemplateChannel.resolveTemplateString(string, variables) ⇒ <code>string</code>\nReplaces the specified variables in the specified string.\n\n**Kind**: static method of [<code>TemplateChannel</code>](#TemplateChannel)  \n**Returns**: <code>string</code> - The modified string.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| string | <code>string</code> | The string which has to be modified. |\n| variables | <code>Record.&lt;string, string&gt;</code> | Each variable (without $) pointing to its value. |\n\n<a name=\"Wheel\"></a>\n\n## Wheel\nInformation about a fixture's wheel.\n\n**Kind**: global class  \n\n* [Wheel](#Wheel)\n    * [new Wheel(wheelName, jsonObject)](#new_Wheel_new)\n    * [.name](#Wheel+name) ⇒ <code>string</code>\n    * [.direction](#Wheel+direction) ⇒ <code>&#x27;CW&#x27;</code> \\| <code>&#x27;CCW&#x27;</code>\n    * [.type](#Wheel+type) ⇒ <code>string</code>\n    * [.slots](#Wheel+slots) ⇒ [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot)\n    * [.getSlot(slotNumber)](#Wheel+getSlot) ⇒ [<code>WheelSlot</code>](#WheelSlot)\n    * [.getAbsoluteSlotIndex(slotNumber)](#Wheel+getAbsoluteSlotIndex) ⇒ <code>number</code>\n    * [.getSlotsOfType(type)](#Wheel+getSlotsOfType) ⇒ [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot)\n\n<a name=\"new_Wheel_new\"></a>\n\n### new Wheel(wheelName, jsonObject)\nCreates a new Wheel instance.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| wheelName | <code>string</code> | The wheel's name, like specified in the JSON. |\n| jsonObject | <code>object</code> | A wheel object from the fixture's JSON data. |\n\n<a name=\"Wheel+name\"></a>\n\n### wheel.name ⇒ <code>string</code>\n**Kind**: instance property of [<code>Wheel</code>](#Wheel)  \n**Returns**: <code>string</code> - The wheel's name.  \n<a name=\"Wheel+direction\"></a>\n\n### wheel.direction ⇒ <code>&#x27;CW&#x27;</code> \\| <code>&#x27;CCW&#x27;</code>\n**Kind**: instance property of [<code>Wheel</code>](#Wheel)  \n**Returns**: <code>&#x27;CW&#x27;</code> \\| <code>&#x27;CCW&#x27;</code> - The direction the wheel's slots are arranged in. Defaults to clockwise.  \n<a name=\"Wheel+type\"></a>\n\n### wheel.type ⇒ <code>string</code>\n**Kind**: instance property of [<code>Wheel</code>](#Wheel)  \n**Returns**: <code>string</code> - The type of the Wheel, i.e. the most frequent slot type (except for animation gobo wheels; the wheel type is AnimationGobo there).  \n<a name=\"Wheel+slots\"></a>\n\n### wheel.slots ⇒ [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot)\n**Kind**: instance property of [<code>Wheel</code>](#Wheel)  \n**Returns**: [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot) - Array of wheel slots.  \n<a name=\"Wheel+getSlot\"></a>\n\n### wheel.getSlot(slotNumber) ⇒ [<code>WheelSlot</code>](#WheelSlot)\n**Kind**: instance method of [<code>Wheel</code>](#Wheel)  \n**Returns**: [<code>WheelSlot</code>](#WheelSlot) - The slot object. Can be a split slot object, if a non-integer index is specified.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| slotNumber | <code>number</code> | The one-based slot number. |\n\n<a name=\"Wheel+getAbsoluteSlotIndex\"></a>\n\n### wheel.getAbsoluteSlotIndex(slotNumber) ⇒ <code>number</code>\n**Kind**: instance method of [<code>Wheel</code>](#Wheel)  \n**Returns**: <code>number</code> - The zero-based slot index, bounded by the number of slots.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| slotNumber | <code>number</code> | The one-based slot number, can be smaller than 1 and greater than the number of slots. |\n\n<a name=\"Wheel+getSlotsOfType\"></a>\n\n### wheel.getSlotsOfType(type) ⇒ [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot)\n**Kind**: instance method of [<code>Wheel</code>](#Wheel)  \n**Returns**: [<code>Array.&lt;WheelSlot&gt;</code>](#WheelSlot) - All slots with the given type.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| type | <code>string</code> | The wheel slot type to search for. |\n\n<a name=\"WheelSlot\"></a>\n\n## WheelSlot\nInformation about a single wheel slot (or a split slot).\n\n**Kind**: global class  \n\n* [WheelSlot](#WheelSlot)\n    * [new WheelSlot(jsonObject, wheel, floorSlot, ceilSlot)](#new_WheelSlot_new)\n    * [.isSplitSlot](#WheelSlot+isSplitSlot) ⇒ <code>boolean</code>\n    * [.type](#WheelSlot+type) ⇒ <code>string</code>\n    * [.nthOfType](#WheelSlot+nthOfType) ⇒ <code>number</code>\n    * [.resource](#WheelSlot+resource) ⇒ [<code>Resource</code>](#Resource) \\| <code>string</code> \\| <code>null</code>\n    * [.name](#WheelSlot+name) ⇒ <code>string</code>\n    * [.colors](#WheelSlot+colors) ⇒ <code>Array.&lt;string&gt;</code> \\| <code>null</code>\n    * [.colorTemperature](#WheelSlot+colorTemperature) ⇒ [<code>Entity</code>](#Entity) \\| <code>null</code>\n    * [.facets](#WheelSlot+facets) ⇒ <code>number</code> \\| <code>null</code>\n    * [.openPercent](#WheelSlot+openPercent) ⇒ [<code>Entity</code>](#Entity) \\| <code>null</code>\n    * [.frostIntensity](#WheelSlot+frostIntensity) ⇒ [<code>Entity</code>](#Entity) \\| <code>null</code>\n    * [.floorSlot](#WheelSlot+floorSlot) ⇒ [<code>WheelSlot</code>](#WheelSlot) \\| <code>null</code>\n    * [.ceilSlot](#WheelSlot+ceilSlot) ⇒ [<code>WheelSlot</code>](#WheelSlot) \\| <code>null</code>\n\n<a name=\"new_WheelSlot_new\"></a>\n\n### new WheelSlot(jsonObject, wheel, floorSlot, ceilSlot)\nCreates a new WheelSlot instance.\n\n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| jsonObject | <code>object</code> \\| <code>null</code> |  | A wheel slot object from the fixture's JSON data. If null, this WheelSlot is a split slot. |\n| wheel | [<code>Wheel</code>](#Wheel) |  | The wheel that this slot belongs to. |\n| floorSlot | [<code>WheelSlot</code>](#WheelSlot) \\| <code>null</code> | <code></code> | For split slots, the WheelSlot instance at the start. |\n| ceilSlot | [<code>WheelSlot</code>](#WheelSlot) \\| <code>null</code> | <code></code> | For split slots, the WheelSlot instance at the end. |\n\n<a name=\"WheelSlot+isSplitSlot\"></a>\n\n### wheelSlot.isSplitSlot ⇒ <code>boolean</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: <code>boolean</code> - True if this WheelSlot instance represents a split slot.  \n<a name=\"WheelSlot+type\"></a>\n\n### wheelSlot.type ⇒ <code>string</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: <code>string</code> - The slot's type.  \n<a name=\"WheelSlot+nthOfType\"></a>\n\n### wheelSlot.nthOfType ⇒ <code>number</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: <code>number</code> - The zero-based index of this slot amongst all slots with the same type in this wheel.  \n<a name=\"WheelSlot+resource\"></a>\n\n### wheelSlot.resource ⇒ [<code>Resource</code>](#Resource) \\| <code>string</code> \\| <code>null</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: [<code>Resource</code>](#Resource) \\| <code>string</code> \\| <code>null</code> - The gobo resource object if it was previously embedded, or the gobo resource reference string, or null if no resource is specified for the slot.  \n<a name=\"WheelSlot+name\"></a>\n\n### wheelSlot.name ⇒ <code>string</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: <code>string</code> - The wheel slot's name.  \n<a name=\"WheelSlot+colors\"></a>\n\n### wheelSlot.colors ⇒ <code>Array.&lt;string&gt;</code> \\| <code>null</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: <code>Array.&lt;string&gt;</code> \\| <code>null</code> - The colors of this wheel slot, or null if this slot has no colors.  \n<a name=\"WheelSlot+colorTemperature\"></a>\n\n### wheelSlot.colorTemperature ⇒ [<code>Entity</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: [<code>Entity</code>](#Entity) \\| <code>null</code> - For Color slots, the slot's color temperature. Null if this slot has no color temperature.  \n<a name=\"WheelSlot+facets\"></a>\n\n### wheelSlot.facets ⇒ <code>number</code> \\| <code>null</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: <code>number</code> \\| <code>null</code> - For Prism slots, the number of prism facets. Null if number of facets is not defined.  \n<a name=\"WheelSlot+openPercent\"></a>\n\n### wheelSlot.openPercent ⇒ [<code>Entity</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: [<code>Entity</code>](#Entity) \\| <code>null</code> - For Iris slots, the slot's openPercent value. Null if this slot has no openPercent value.  \n<a name=\"WheelSlot+frostIntensity\"></a>\n\n### wheelSlot.frostIntensity ⇒ [<code>Entity</code>](#Entity) \\| <code>null</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: [<code>Entity</code>](#Entity) \\| <code>null</code> - For Frost slots, the slot's frost intensity. Null if this slot has no frost intensity.  \n<a name=\"WheelSlot+floorSlot\"></a>\n\n### wheelSlot.floorSlot ⇒ [<code>WheelSlot</code>](#WheelSlot) \\| <code>null</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: [<code>WheelSlot</code>](#WheelSlot) \\| <code>null</code> - For split slots, the floor (start) slot. Null for non-split slots.  \n<a name=\"WheelSlot+ceilSlot\"></a>\n\n### wheelSlot.ceilSlot ⇒ [<code>WheelSlot</code>](#WheelSlot) \\| <code>null</code>\n**Kind**: instance property of [<code>WheelSlot</code>](#WheelSlot)  \n**Returns**: [<code>WheelSlot</code>](#WheelSlot) \\| <code>null</code> - For split slots, the ceil (end) slot. Null for non-split slots.  \n<a name=\"Resolution\"></a>\n\n## Resolution : <code>number</code>\n1 for 8bit, 2 for 16bit, ...\n\n**Kind**: global typedef  \n<a name=\"TriggerCapability\"></a>\n\n## TriggerCapability : <code>object</code>\n**Kind**: global typedef  \n**Properties**\n\n| Name | Type | Description |\n| --- | --- | --- |\n| dmxRange | [<code>Range</code>](#Range) | The DMX range that triggers the switching channel. |\n| switchTo | <code>string</code> | The channel to switch to in the given DMX range. |\n\n<a name=\"SwitchingChannelBehavior\"></a>\n\n## SwitchingChannelBehavior : <code>&#x27;keyOnly&#x27;</code> \\| <code>&#x27;defaultOnly&#x27;</code> \\| <code>&#x27;switchedOnly&#x27;</code> \\| <code>&#x27;all&#x27;</code>\n**Kind**: global typedef  \n"
  },
  {
    "path": "docs/plugins.md",
    "content": "# Plugins\n\nThe aim of the *Open Fixture Library* is to import and export our fixture definitions from / to fixture formats of third-party lighting control software, for example [QLC+](https://github.com/mcallegari/qlcplus)'s `.qfx` format. A plugin is a converter between our format and one such external format. It implements an import and / or export method that parses / generates the third-party format.\n\nEach plugin has its own directory `plugins/<plugin-key>/` which contains all information, methods and tests about the external format. You have to provide a `plugin.json` file in that directory, containing at least the plugin name, description and one or more links. See the [schema](../schemas/plugin.json) or other plugins' `plugin.json` files as a reference. This data is also used to create the about page for this plugin in the UI.\n\nBe sure to always run `npm run build` after editing `plugin.json` or adding export/import scripts and export tests.\n\nYou can try plugins from the command line:\n\n```bash\n# Import\nnode cli/import-fixture.js -p <plugin> <filename>\nnode cli/import-fixture.js -h # Help message\n\n# Export\nnode cli/export-fixture.js -p <plugin> <fixture> [<more fixtures>]\n```\n\n## Exporting\n\nIf exporting is supported, create a `plugins/<plugin-key>/export.js` module that provides the plugin name, version and a method that generates the needed third-party files out of an given array of [Fixture](model-api.md#Fixture) objects. This method should return a Promise of an array of objects for each file that should be exported / downloadable; the files are zipped together automatically if necessary. A file object looks like this:\n\n<!-- eslint-skip -->\n```js\n{\n  name: 'filename.ext', // Required, may include forward slashes to generate a folder structure\n  content: 'file content', // Required\n  mimetype: 'text/plain', // Required\n  fixtures: [fixA, fixB], // Optional, list of Fixture objects that are described in this file; may be omitted if the file doesn't belong to any fixture (e.g. manufacturer information)\n  mode: '8ch' // Optional, mode's shortName if this file only describes a single mode\n}\n```\n\nA very simple export plugin looks like this:\n\n```js\nexport const version = '0.1.0'; // semantic versioning of export plugin\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects, see our fixture model\n * @param {object} options Some global options, for example:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} All generated files (see file schema above)\n */\nexport async function exportFixtures(fixtures, options) {\n  const outfiles = [];\n\n  for (const fixture of fixtures) {\n    for (const mode of fixture.modes) {\n      outfiles.push({\n        name: `${fixture.manufacturer.key}-${fixture.key}-${mode.shortName}.xml`,\n\n        // That's just an example! Usually, the (way larger) file contents are\n        // computed using several (possibly asynchronous) helper functions\n        content: `<title>${fixture.name}: ${mode.channels.length}ch</title>`,\n        mimetype: 'application/xml',\n      });\n    }\n  }\n\n  return outfiles;\n}\n```\n\n## Importing\n\nIf importing is supported, create a `plugins/<plugin-key>/import.js` module that exports the plugin name, version and a method that creates OFL fixture definitions out of a given third-party file.\n\nAs file parsing (like XML processing) can be asynchronous, the import method returns its results asynchronously using a [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) that resolves to an object that looks like this:\n\n<!-- eslint-skip -->\n```js\n{\n  // Imported manufacturer data; like in manufacturers.json:\n  // key: 'manufacturer-key', value: manufacturer data\n  manufacturers: {},\n  // Imported fixtures\n  // key: 'manufacturer-key/fixture-key', value: like in a fixture JSON\n  fixtures: {},\n  // Warnings about each imported fixture\n  // (e.g. if the definition was incorrect or lacks required information)\n  // key: 'manufacturer-key/fixture-key', value: array of strings (warning messages)\n  warnings: {}\n};\n```\n\nIf the file can not be parsed by the import plugin or contains errors, the returned Promise should reject with an Error.\n\nExample:\n\n```js\nexport const version = '0.1.0'; // semantic versioning of import plugin\n\n/**\n * @param {Buffer} buffer The imported file.\n * @param {string} fileName The imported file's name.\n * @param {string} authorName The importer's name.\n * @returns {Promise<object, Error>} A Promise that resolves to an out object (see above) or rejects with an error.\n */\nexport async function importFixtures(buffer, fileName, authorName) {\n  const out = {\n    manufacturers: {},\n    fixtures: {},\n    warnings: {},\n  };\n\n  // just an example\n  const manufacturerKey = 'cameo';\n  const fixtureKey = 'thunder-wash-600-rgb'; // use a sanitized key as it's used as filename!\n\n  const fixtureObject = {};\n  out.warnings[`${manufacturerKey}/${fixtureKey}`] = [];\n\n  const fileContent = buffer.toString();\n  const couldNotParse = fileContent.includes('Error');\n  if (couldNotParse) {\n    throw new Error(`Could not parse '${fileName}'.`);\n  }\n\n  fixtureObject.name = 'Thunder Wash 600 RGB';\n\n  // Add warning if a necessary property is not included in parsed file\n  out.warnings[`${manufacturerKey}/${fixtureKey}`].push('Could not parse categories, please specify them manually.');\n\n  // That's the imported fixture\n  out.fixtures[`${manufacturerKey}/${fixtureKey}`] = fixtureObject;\n\n  return out;\n}\n```\n\n## Export tests\n\nWe want to run unit tests wherever possible (see [Testing](testing.md)), that's why it's possible to write plugin specific tests for exported fixtures, so called export tests. Of course they're only possible if the plugin provides an export module.\n\nA plugin's export test takes an exported file object as argument and evaluates it against plugin-specific requirements. For example, there is a [QLC+ export test](../plugins/qlcplus_4.12.2/exportTests/xsd-schema-conformity.js) that compares the generated XML file with the given QLC+ XSD fixture schema (if an official XML schema is available, it should definitely be used in an export test). We run these export tests automatically using GitHub Actions.\n\nEach test module should be located at `plugins/<plugin-key>/exportTests/<export-test-key>.js`. Here's a dummy test illustrating the structure:\n\n```js\nimport xml2js from 'xml2js';\n\n/**\n * @param {object} exportFile The file returned by the plugins' export module.\n * @param {string} exportFile.name File name, may include slashes to provide a folder structure.\n * @param {string} exportFile.content File content.\n * @param {string} exportFile.mimetype File mime type.\n * @param {Fixture[] | null} exportFile.fixtures Fixture objects that are described in given file; may be omitted if the file doesn't belong to any fixture (e.g. manufacturer information).\n * @param {string | null} exportFile.mode Mode's shortName if given file only describes a single mode.\n * @returns {Promise<void, string[] | string>} Resolve when the test passes or reject with an array of errors or one error if the test fails.\n */\nexport default async function testValueCorrectness(exportFile) {\n  const xml = await xml2js.parseStringPromise(exportFile.content);\n\n  const errors = [];\n\n  // the lighting software crashes if the name is empty, so we must ensure that this won't happen\n  // (just an example)\n  if (!('Name' in xml.Fixture) || xml.Fixture.Name[0] === '') {\n    errors.push('Name missing');\n  }\n\n  if (errors.length > 0) {\n    throw errors;\n  }\n\n  // everything's ok\n}\n```\n\nYou can execute an export test from the command line:\n\n```bash\nnode cli/run-export-test.js -p <plugin> [ <fixtures> ]\nnode cli/run-export-test.js -h # Help message\n```\n\nExport tests are automatically run in pull requests, where they add a comment with the changes introduced by the pull request.\n"
  },
  {
    "path": "docs/rest-api.md",
    "content": "<!-- Generator: Widdershins v4.0.1 -->\n\n<h1 id=\"open-fixture-library-api\">Open Fixture Library API v1.0</h1>\n\n> Scroll down for example requests and responses.\n\nBase URLs:\n\n* <a href=\"https://open-fixture-library.org/api/v1\">https://open-fixture-library.org/api/v1</a>\n\n* <a href=\"http://localhost:3000/api/v1\">http://localhost:3000/api/v1</a>\n\n<h1 id=\"open-fixture-library-api-root\">root</h1>\n\n## getSearchResults\n\n<a id=\"opIdgetSearchResults\"></a>\n\n`POST /get-search-results`\n\nReturn search results for given parameters.\n\n> Body parameter\n\n```json\n{\n  \"searchQuery\": \"string\",\n  \"manufacturersQuery\": [\n    \"string\"\n  ],\n  \"categoriesQuery\": [\n    \"string\"\n  ]\n}\n```\n\n<h3 id=\"getsearchresults-parameters\">Parameters</h3>\n\n|Name|In|Type|Required|Description|\n|---|---|---|---|---|\n|searchQuery|body|string|true|none|\n|manufacturersQuery|body|[string]|true|none|\n|categoriesQuery|body|[string]|true|none|\n\n> Example responses\n\n> 200 Response\n\n```json\n[\n  \"showtec/phantom-3r-beam\",\n  \"showtec/phantom-50-led-spot\",\n  \"showtec/phantom-140-led-spot\",\n  \"showtec/phantom-matrix-fx\"\n]\n```\n\n<h3 id=\"getsearchresults-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Fixture keys matching the queries.|Inline|\n\n<h3 id=\"getsearchresults-responseschema\">Response Schema</h3>\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n## createFeedbackIssue\n\n<a id=\"opIdcreateFeedbackIssue\"></a>\n\n`POST /submit-feedback`\n\nTakes the input from the client side script and creates a GitHub issue with the given feedback.\n\n> Body parameter\n\n```json\n{\n  \"type\": \"fixture\",\n  \"context\": \"string\",\n  \"location\": \"string\",\n  \"helpWanted\": \"string\",\n  \"message\": \"string\",\n  \"githubUsername\": \"string\"\n}\n```\n\n<h3 id=\"createfeedbackissue-parameters\">Parameters</h3>\n\n|Name|In|Type|Required|Description|\n|---|---|---|---|---|\n|type|body|string|true|none|\n|context|body|string|true|The fixture key or plugin key.|\n|location|body|string¦null|true|none|\n|helpWanted|body|string¦null|true|none|\n|message|body|string|true|none|\n|githubUsername|body|string|true|none|\n\n#### Enumerated Values\n\n|Parameter|Value|\n|---|---|\n|type|fixture|\n|type|capability|\n|type|plugin|\n\n> Example responses\n\n> 201 Response\n\n```json\n{\n  \"issueUrl\": \"https://github.com/OpenLightingProject/open-fixture-library/issues/1154\"\n}\n```\n\n<h3 id=\"createfeedbackissue-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|Issue created or error occured.|Inline|\n\n<h3 id=\"createfeedbackissue-responseschema\">Response Schema</h3>\n\nStatus Code **201**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» issueUrl|string¦null|true|none|none|\n|» error|string¦null|true|none|none|\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n<h1 id=\"open-fixture-library-api-fixtures\">fixtures</h1>\n\n## createFixtureFromEditor\n\n<a id=\"opIdcreateFixtureFromEditor\"></a>\n\n`POST /fixtures/from-editor`\n\nConverts the given editor fixture data into OFL fixtures and responds with a FixtureCreateResult.\n\n> Body parameter\n\n```json\n[\n  {}\n]\n```\n\n> Example responses\n\n> 201 Response\n\n```json\n{\n  \"manufacturers\": {\n    \"man-key\": {\n      \"name\": \"Manufacturer name\",\n      \"website\": \"https://example.org\"\n    }\n  },\n  \"fixtures\": {\n    \"man-key/fix-key\": {\n      \"name\": \"Fixture name\",\n      \"$comment\": \"…\"\n    }\n  },\n  \"warnings\": {\n    \"man-key/fix-key\": [\n      \"Some warning for fixture man-key/fix-key.\"\n    ]\n  },\n  \"errors\": {\n    \"man-key/fix-key\": []\n  }\n}\n```\n\n<h3 id=\"createfixturefromeditor-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|Fixture successfully imported|Inline|\n|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request|Inline|\n\n<h3 id=\"createfixturefromeditor-responseschema\">Response Schema</h3>\n\nStatus Code **201**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» manufacturers|object|true|none|none|\n|» fixtures|object|true|none|none|\n|» warnings|object|true|none|none|\n|» errors|object|true|none|none|\n\nStatus Code **400**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» error|string|true|none|none|\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n## importFixtureFile\n\n<a id=\"opIdimportFixtureFile\"></a>\n\n`POST /fixtures/import`\n\nImports the uploaded fixture file and responds with a FixtureCreateResult.\n\n> Body parameter\n\n```json\n{\n  \"plugin\": \"string\",\n  \"fileName\": \"string\",\n  \"fileContentBase64\": \"string\",\n  \"author\": \"string\"\n}\n```\n\n<h3 id=\"importfixturefile-parameters\">Parameters</h3>\n\n|Name|In|Type|Required|Description|\n|---|---|---|---|---|\n|plugin|body|string|true|none|\n|fileName|body|string|true|none|\n|fileContentBase64|body|string(base64)|true|none|\n|author|body|string|true|none|\n\n> Example responses\n\n> 201 Response\n\n```json\n{\n  \"manufacturers\": {\n    \"man-key\": {\n      \"name\": \"Manufacturer name\",\n      \"website\": \"https://example.org\"\n    }\n  },\n  \"fixtures\": {\n    \"man-key/fix-key\": {\n      \"name\": \"Fixture name\",\n      \"$comment\": \"…\"\n    }\n  },\n  \"warnings\": {\n    \"man-key/fix-key\": [\n      \"Some warning for fixture man-key/fix-key.\"\n    ]\n  },\n  \"errors\": {\n    \"man-key/fix-key\": []\n  }\n}\n```\n\n<h3 id=\"importfixturefile-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|Fixture successfully imported|Inline|\n|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request|Inline|\n\n<h3 id=\"importfixturefile-responseschema\">Response Schema</h3>\n\nStatus Code **201**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» manufacturers|object|true|none|none|\n|» fixtures|object|true|none|none|\n|» warnings|object|true|none|none|\n|» errors|object|true|none|none|\n\nStatus Code **400**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» error|string|true|none|none|\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n## submitFixtures\n\n<a id=\"opIdsubmitFixtures\"></a>\n\n`POST /fixtures/submit`\n\nCreates a GitHub pull request with the given fixture data. Includes warnings, errors, GitHub username and GitHub comment in the PR description.\n\n> Body parameter\n\n```json\n{\n  \"fixtureCreateResult\": {\n    \"manufacturers\": {\n      \"man-key\": {\n        \"name\": \"Manufacturer name\",\n        \"website\": \"https://example.org\"\n      }\n    },\n    \"fixtures\": {\n      \"man-key/fix-key\": {\n        \"name\": \"Fixture name\",\n        \"$comment\": \"…\"\n      }\n    },\n    \"warnings\": {\n      \"man-key/fix-key\": [\n        \"Some warning for fixture man-key/fix-key.\"\n      ]\n    },\n    \"errors\": {\n      \"man-key/fix-key\": []\n    }\n  },\n  \"githubUsername\": \"string\",\n  \"githubComment\": \"string\"\n}\n```\n\n<h3 id=\"submitfixtures-parameters\">Parameters</h3>\n\n|Name|In|Type|Required|Description|\n|---|---|---|---|---|\n|fixtureCreateResult|body|object|true|none|\n|» manufacturers|body|object|true|none|\n|» fixtures|body|object|true|none|\n|» warnings|body|object|true|none|\n|» errors|body|object|true|none|\n|githubUsername|body|string¦null|true|none|\n|githubComment|body|string¦null|true|none|\n\n> Example responses\n\n> 201 Response\n\n```json\n{\n  \"pullRequestUrl\": \"string\"\n}\n```\n\n<h3 id=\"submitfixtures-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|OK|Inline|\n|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request|Inline|\n\n<h3 id=\"submitfixtures-responseschema\">Response Schema</h3>\n\nStatus Code **201**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» pullRequestUrl|string|true|none|none|\n\nStatus Code **400**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» error|string|true|none|none|\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n<h1 id=\"open-fixture-library-api-manufacturers\">manufacturers</h1>\n\n## getManufacturers\n\n<a id=\"opIdgetManufacturers\"></a>\n\n`GET /manufacturers`\n\nReturns general information about all manufacturers.\n\n> Example responses\n\n> 200 Response\n\n```json\n{\n  \"property1\": {\n    \"name\": \"string\",\n    \"fixtureCount\": 0,\n    \"color\": \"string\"\n  },\n  \"property2\": {\n    \"name\": \"string\",\n    \"fixtureCount\": 0,\n    \"color\": \"string\"\n  }\n}\n```\n\n<h3 id=\"getmanufacturers-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline|\n\n<h3 id=\"getmanufacturers-responseschema\">Response Schema</h3>\n\nStatus Code **200**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» **additionalProperties**|object|false|none|none|\n|»» name|string|true|none|none|\n|»» fixtureCount|integer|true|none|none|\n|»» color|string|true|none|none|\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n## getManufacturerByKey\n\n<a id=\"opIdgetManufacturerByKey\"></a>\n\n`GET /manufacturers/{manufacturerKey}`\n\nReturns information about a specific manufacturer.\n\n<h3 id=\"getmanufacturerbykey-parameters\">Parameters</h3>\n\n|Name|In|Type|Required|Description|\n|---|---|---|---|---|\n|manufacturerKey|path|string|true|none|\n\n> Example responses\n\n> 200 Response\n\n```json\n{\n  \"key\": \"string\",\n  \"name\": \"string\",\n  \"comment\": \"string\",\n  \"website\": \"string\",\n  \"rdmId\": 0,\n  \"color\": \"string\",\n  \"fixtures\": [\n    {\n      \"key\": \"string\",\n      \"name\": \"string\",\n      \"categories\": [\n        \"string\"\n      ]\n    }\n  ]\n}\n```\n\n<h3 id=\"getmanufacturerbykey-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline|\n|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|Not Found|Inline|\n\n<h3 id=\"getmanufacturerbykey-responseschema\">Response Schema</h3>\n\nStatus Code **200**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» key|string|true|none|none|\n|» name|string|true|none|none|\n|» comment|string|false|none|none|\n|» website|string|false|none|none|\n|» rdmId|integer|false|none|none|\n|» color|string|true|none|none|\n|» fixtures|[object]|true|none|none|\n|»» key|string|true|none|none|\n|»» name|string|true|none|none|\n|»» categories|[string]|false|none|none|\n\nStatus Code **404**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» error|string|true|none|none|\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n<h1 id=\"open-fixture-library-api-plugins\">plugins</h1>\n\n## getPlugins\n\n<a id=\"opIdgetPlugins\"></a>\n\n`GET /plugins`\n\nReturns general information about import and export plugins.\n\n> Example responses\n\n> 200 Response\n\n```json\n{\n  \"importPlugins\": [\n    \"string\"\n  ],\n  \"exportPlugins\": [\n    \"string\"\n  ],\n  \"data\": {\n    \"property1\": {\n      \"name\": \"string\",\n      \"outdated\": null,\n      \"newPlugin\": \"string\",\n      \"importPluginVersion\": \"string\",\n      \"exportPluginVersion\": \"string\",\n      \"exportTests\": [\n        \"string\"\n      ]\n    },\n    \"property2\": {\n      \"name\": \"string\",\n      \"outdated\": null,\n      \"newPlugin\": \"string\",\n      \"importPluginVersion\": \"string\",\n      \"exportPluginVersion\": \"string\",\n      \"exportTests\": [\n        \"string\"\n      ]\n    }\n  }\n}\n```\n\n<h3 id=\"getplugins-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline|\n\n<h3 id=\"getplugins-responseschema\">Response Schema</h3>\n\nStatus Code **200**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» importPlugins|[string]|true|none|none|\n|» exportPlugins|[string]|true|none|none|\n|» data|object|true|none|none|\n|»» **additionalProperties**|object|false|none|none|\n|»»» name|string|true|none|none|\n|»»» outdated|any|false|none|none|\n|»»» newPlugin|string|false|none|none|\n|»»» importPluginVersion|string|false|none|none|\n|»»» exportPluginVersion|string|false|none|none|\n|»»» exportTests|[string]|false|none|none|\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n## getPluginByKey\n\n<a id=\"opIdgetPluginByKey\"></a>\n\n`GET /plugins/{pluginKey}`\n\nReturns information about a specific import and export plugin. If an outdated plugin is requested, the information for the renamed plugin is returned.\n\n<h3 id=\"getpluginbykey-parameters\">Parameters</h3>\n\n|Name|In|Type|Required|Description|\n|---|---|---|---|---|\n|pluginKey|path|string|true|none|\n\n> Example responses\n\n> 200 Response\n\n```json\n{\n  \"key\": \"string\",\n  \"name\": \"string\",\n  \"previousVersions\": {\n    \"property1\": \"string\",\n    \"property2\": \"string\"\n  },\n  \"description\": \"string\",\n  \"links\": {\n    \"property1\": \"string\",\n    \"property2\": \"string\"\n  },\n  \"fixtureUsage\": \"string\",\n  \"fileLocations\": {\n    \"subDirectoriesAllowed\": true,\n    \"property1\": {\n      \"main\": \"string\",\n      \"user\": \"string\"\n    },\n    \"property2\": {\n      \"main\": \"string\",\n      \"user\": \"string\"\n    }\n  },\n  \"additionalInfo\": \"string\",\n  \"helpWanted\": \"string\",\n  \"exportPluginVersion\": \"string\",\n  \"importPluginVersion\": \"string\"\n}\n```\n\n<h3 id=\"getpluginbykey-responses\">Responses</h3>\n\n|Status|Meaning|Description|Schema|\n|---|---|---|---|\n|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|none|Inline|\n|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|Not Found|Inline|\n\n<h3 id=\"getpluginbykey-responseschema\">Response Schema</h3>\n\nStatus Code **200**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» key|string|true|none|none|\n|» name|string|true|none|none|\n|» previousVersions|object|true|none|none|\n|»» **additionalProperties**|string|false|none|none|\n|» description|string|true|none|none|\n|» links|object|true|none|none|\n|»» **additionalProperties**|string|false|none|none|\n|» fixtureUsage|string|false|none|none|\n|» fileLocations|object|false|none|none|\n|»» **additionalProperties**|object|false|none|none|\n|»»» main|string|false|none|none|\n|»»» user|string|false|none|none|\n|»» subDirectoriesAllowed|boolean|false|none|none|\n|» additionalInfo|string|false|none|none|\n|» helpWanted|string|false|none|none|\n|» exportPluginVersion|string|false|none|none|\n|» importPluginVersion|string|false|none|none|\n\nStatus Code **404**\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|» error|string|true|none|none|\n\n<aside class=\"success\">\nThis operation does not require authentication\n</aside>\n\n# Schemas\n\n<h2 id=\"tocS_FixtureCreateResult\">FixtureCreateResult</h2>\n<!-- backwards compatibility -->\n<a id=\"schemafixturecreateresult\"></a>\n<a id=\"schema_FixtureCreateResult\"></a>\n<a id=\"tocSfixturecreateresult\"></a>\n<a id=\"tocsfixturecreateresult\"></a>\n\n```json\n{\n  \"manufacturers\": {\n    \"man-key\": {\n      \"name\": \"Manufacturer name\",\n      \"website\": \"https://example.org\"\n    }\n  },\n  \"fixtures\": {\n    \"man-key/fix-key\": {\n      \"name\": \"Fixture name\",\n      \"$comment\": \"…\"\n    }\n  },\n  \"warnings\": {\n    \"man-key/fix-key\": [\n      \"Some warning for fixture man-key/fix-key.\"\n    ]\n  },\n  \"errors\": {\n    \"man-key/fix-key\": []\n  }\n}\n```\n\n### Properties\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|manufacturers|object|true|none|none|\n|fixtures|object|true|none|none|\n|warnings|object|true|none|none|\n|errors|object|true|none|none|\n\n<h2 id=\"tocS_Error\">Error</h2>\n<!-- backwards compatibility -->\n<a id=\"schemaerror\"></a>\n<a id=\"schema_Error\"></a>\n<a id=\"tocSerror\"></a>\n<a id=\"tocserror\"></a>\n\n```json\n{\n  \"error\": \"Some error message.\"\n}\n```\n\n### Properties\n\n|Name|Type|Required|Restrictions|Description|\n|---|---|---|---|---|\n|error|string|true|none|none|\n\n"
  },
  {
    "path": "docs/testing.md",
    "content": "# Testing\n\nWe try to develop unit tests wherever possible. They test specific components of our project by respecting the [F.I.R.S.T Principles of Unit Testing](https://howtodoinjava.com/best-practices/first-principles-for-good-tests/):\n\n* **Fast** – Tests that need too long time would annoy the workflow\n* **Isolated** – Tests should not affect each other. Continuous Integration testing helps a lot at fulfilling this principle.\n* **Repeatable** – Tests should be independent from the current environment and other side effects.\n* **Self-Validating** – A test should either pass or fail, no manual inspection is needed to determine the state.\n* **Timely** – With new features, also new tests have to be implemented\n\nTests are located in the [`tests/`](../tests/) directory (surprise!), one test per file. They can be called manually except of the GitHub tests in [`tests/github/`](../tests/github/) (see below).\n\nWe use [GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions) for continuous integration (CI): It runs our specified tests with every GitHub commit. The exit code returned by a test script tells GitHub Actions whether it has passed or failed: Tests with `0` exit code (in Node.js: `process.exit(0);`) have passed, all others (non-zero exit codes) have failed.\n\nThe GitHub repository is configured such that pull requests with failing tests can't be merged. To implement optional tests that don't prevent a PR from being merged, just make it always pass (with exit code `0`) and warn the developers via console output or a GitHub comment.\n\nSome tests rely on the information what files have been changed in a PR (*GitHub tests*, located in `tests/github/`). They use the helper module [`pull-request.js`](../tests/github/pull-request.js) to identify the current pull request and commit hash and to add comments. They can't be called manually (because there is no pull request locally). The `pull-request.js` module can also be used by other non-GitHub tests to create warning comments.\n\nRunning the test suite against the whole fixture library would be too much effort in most cases. The test fixture collection ([`tests/test-fixtures.json`](../tests/test-fixtures.json)) is a set of test fixtures that cover all defined [Fixture features](fixture-features.md) (while keeping the set as small as possible). Running tests only against these fixtures ensures a broad coverage with minimal effort. The set can be generated by calling [`cli/build-test-fixtures.js`](../cli/build-test-fixtures.js) or simply `npm run build`.\n"
  },
  {
    "path": "docs/ui.md",
    "content": "# User Interface (UI) / Website\n\nOur website [open-fixture-library.org/](https://open-fixture-library.org/) is a [Nuxt](https://nuxtjs.org/) instance running on an [Express](https://expressjs.com/) server. That means that every page is a [Vue](https://vuejs.org/) component that is rendered on the server. Users that have JavaScript enabled can navigate purely on the client-side though, so only a small page-specific JavaScript file is downloaded via [XHR](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) and rendered in the browser. All that is handled automatically by Nuxt.\n\n\n## Local development server\n\nLocally, running `npm run dev` (after the [initial setup](README.md#local-installation)) starts the development server at `http://localhost:3000/` with hot module reloading, i.e. a changed Vue component file automatically patches only that component without having to reload the whole page. The port can be changed with the environment variable `PORT`, e.g. in the `.env` file.\n\n\n## Folder structure\n\n*Note: for non-UI-related folders, see [README.md](README.md).*\n\n* `ui/`\n  - `api/` – Handlers that respond to AJAX resquests from the frontend (see the [REST API reference](rest-api.md))\n  - `assets/` – Icons, scripts, stylesheets, etc.\n  - `components/` – Reusable Vue components\n  - `express-middleware/` – Functions that directly hook into Express.js (the server side router)\n  - `layouts/` – Whole-page [Nuxt layouts](https://nuxtjs.org/guide/views#layouts)\n  - `pages/` – All website pages (in the [correct directory structure](https://nuxtjs.org/guide/routing)) as Vue components\n  - `plugins/` – [Nuxt plugins](https://nuxtjs.org/guide/plugins) that load and instantiate external modules\n  - `static/` – Resources that don't need processing before being served\n* `nuxt.config.js`\n\n\n## Deployment\n\nEvery time a new pull request is merged into the master branch, the new version is automatically deployed to <https://open-fixture-library.org/> (see the [`server/` directory](../server/)).\n"
  },
  {
    "path": "eslint.config.js",
    "content": "import { fixupPluginRules } from '@eslint/compat';\nimport eslintJs from '@eslint/js';\nimport eslintMarkdown from '@eslint/markdown';\nimport eslintPluginStylistic from '@stylistic/eslint-plugin';\nimport eslintPluginVitest from '@vitest/eslint-plugin';\nimport eslintPluginImport from 'eslint-plugin-import';\nimport eslintPluginJsdoc from 'eslint-plugin-jsdoc';\nimport { configs as eslintPluginJsoncConfigs } from 'eslint-plugin-jsonc';\nimport eslintPluginNuxt from 'eslint-plugin-nuxt';\nimport eslintPluginPromise from 'eslint-plugin-promise';\nimport eslintPluginSonarjs from 'eslint-plugin-sonarjs';\nimport eslintPluginUnicorn from 'eslint-plugin-unicorn';\nimport eslintPluginVue from 'eslint-plugin-vue';\nimport eslintPluginVueA11y from 'eslint-plugin-vuejs-accessibility';\nimport globals from 'globals';\n\nconst eslintPluginNuxtConfigRecommended = {\n  files: ['**/*.{js,vue}'],\n  plugins: {\n    nuxt: fixupPluginRules(eslintPluginNuxt),\n  },\n  rules: {\n    ...eslintPluginNuxt.configs.base.rules,\n    ...eslintPluginNuxt.configs.recommended.rules,\n    'nuxt/require-func-head': 'error',\n  },\n};\n\nconst stylisticEslintConfig = eslintPluginStylistic.configs.customize({\n  arrowParens: true,\n  semi: true,\n});\n\nconst enabledRuleParameters = {\n  // Core ESLint rules\n  'accessor-pairs': [],\n  'camelcase': [],\n  'consistent-return': [],\n  'curly': ['all'],\n  'dot-notation': [],\n  'eqeqeq': ['always', { null: 'ignore' }],\n  'getter-return': [],\n  'grouped-accessor-pairs': ['getBeforeSet'],\n  'guard-for-in': [],\n  'no-array-constructor': [],\n  'no-bitwise': [],\n  'no-constant-binary-expression': [],\n  'no-else-return': [{ allowElseIf: false }],\n  'no-empty': [],\n  'no-empty-function': [],\n  'no-irregular-whitespace': [],\n  'no-lonely-if': [],\n  'no-loop-func': [],\n  'no-nested-ternary': [],\n  'no-object-constructor': [],\n  'no-prototype-builtins': [],\n  'no-restricted-imports': [{\n    name: 'fs',\n    message: 'Please use \\'fs/promises\\' instead.',\n  }],\n  'no-return-assign': [],\n  'no-return-await': [],\n  'no-shadow': [{\n    builtinGlobals: false,\n    allow: ['_'], // allow placeholder parameters that aren't used anyway\n  }],\n  'no-template-curly-in-string': [],\n  'no-unsafe-optional-chaining': [{ disallowArithmeticOperators: true }],\n  'no-unused-vars': [{ args: 'none' }],\n  'no-unused-expressions': [],\n  'no-useless-assignment': [],\n  'no-var': [],\n  'object-shorthand': [],\n  'prefer-arrow-callback': [],\n  'prefer-const': [{ destructuring: 'all' }],\n  'prefer-object-spread': [],\n  'prefer-rest-params': [],\n  'prefer-template': [],\n  'radix': [],\n\n  // eslint-plugin-stylistic\n  '@stylistic/curly-newline': ['always'],\n  '@stylistic/function-call-spacing': [],\n  '@stylistic/linebreak-style': [],\n  '@stylistic/no-confusing-arrow': [],\n  '@stylistic/quotes': ['single'],\n\n  // eslint-plugin-import\n  'import/extensions': ['ignorePackages'],\n  'import/first': [],\n  'import/newline-after-import': [],\n  'import/no-commonjs': [{ allowConditionalRequire: false }],\n  'import/no-dynamic-require': [],\n  'import/no-unresolved': [{\n    ignore: ['^@octokit/rest$', '^uuid$'],\n  }],\n  'import/order': [{\n    'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object'],\n    'alphabetize': {\n      order: 'asc',\n      caseInsensitive: true,\n      orderImportKind: 'desc',\n    },\n    'named': {\n      enabled: true,\n      cjsExports: false,\n    },\n    'newlines-between': 'never',\n  }],\n\n  // eslint-plugin-jsdoc\n  'jsdoc/check-alignment': [],\n  'jsdoc/check-indentation': [],\n  'jsdoc/check-param-names': [],\n  'jsdoc/check-syntax': [],\n  'jsdoc/check-tag-names': [],\n  'jsdoc/check-types': [],\n  'jsdoc/implements-on-classes': [],\n  'jsdoc/require-jsdoc': [{\n    enableFixer: false,\n    require: {\n      FunctionDeclaration: true,\n      MethodDefinition: true,\n      ClassDeclaration: true,\n      ArrowFunctionExpression: false,\n      FunctionExpression: false,\n    },\n  }],\n  'jsdoc/require-param': [],\n  'jsdoc/require-param-description': [],\n  'jsdoc/require-param-name': [],\n  'jsdoc/require-param-type': [],\n  'jsdoc/require-returns': [],\n  'jsdoc/require-returns-check': [],\n  'jsdoc/prefer-import-tag': [{ enableFixer: true, exemptTypedefs: false }],\n  'jsdoc/require-returns-description': [],\n  'jsdoc/require-returns-type': [],\n  'jsdoc/valid-types': [],\n\n  // eslint-plugin-jsonc\n  'jsonc/auto': [],\n\n  // eslint-plugin-promise\n  'promise/no-callback-in-promise': [],\n  'promise/no-multiple-resolved': [],\n  'promise/no-nesting': [],\n  'promise/no-promise-in-callback': [],\n  'promise/no-return-in-finally': [],\n  'promise/prefer-await-to-then': [],\n  'promise/valid-params': [],\n\n  // eslint-plugin-sonarjs\n  'sonarjs/no-inverted-boolean-check': [],\n\n  // eslint-plugin-unicorn\n  'unicorn/import-style': [{\n    styles: {\n      'fs/promises': { named: true },\n    },\n  }],\n  'unicorn/prefer-export-from': [{ ignoreUsedVariables: true }],\n  'unicorn/prevent-abbreviations': [{\n    replacements: {\n      ref: false,\n      env: false,\n      man: { manufacturer: true },\n      fix: { fixture: true },\n      ch: { channel: true },\n      cap: { capability: true },\n      caps: { capabilities: true },\n      cat: { category: true },\n      cats: { categories: true },\n    },\n  }],\n  'unicorn/text-encoding-identifier-case': [{ withDash: true }],\n\n  // eslint-plugin-vue\n  'vue/block-lang': [{\n    script: { allowNoLang: true },\n    style: { lang: 'scss' },\n    template: { allowNoLang: true },\n  }],\n  'vue/block-order': [{\n    order: ['template', 'style[scoped]', 'style:not([scoped])', 'script'],\n  }],\n  'vue/component-options-name-casing': [],\n  'vue/component-name-in-template-casing': ['PascalCase', {\n    registeredComponentsOnly: false,\n  }],\n  'vue/enforce-style-attribute': [],\n  'vue/html-button-has-type': [],\n  'vue/html-closing-bracket-newline': [{\n    singleline: 'never',\n    multiline: 'never',\n  }],\n  'vue/match-component-file-name': [{\n    extensions: ['vue'],\n    shouldMatchCase: true,\n  }],\n  'vue/match-component-import-name': [],\n  'vue/max-attributes-per-line': [{ singleline: 3 }],\n  'vue/next-tick-style': [],\n  'vue/no-boolean-default': ['default-false'],\n  'vue/no-duplicate-class-names': [],\n  'vue/no-empty-component-block': [],\n  'vue/no-undef-components': [{\n    ignorePatterns: [\n      '^Ofl(Svg|Time)$', // global components\n      '^Nuxt(Link)?$', '^ClientOnly$', // Nuxt components\n      '^VueForm$', '^Validate$', '^FieldMessages$', // VueForm components\n    ],\n  }],\n  'vue/no-undef-directives': [],\n  'vue/no-undef-properties': [],\n  'vue/no-unused-emit-declarations': [],\n  'vue/no-unused-properties': [{\n    groups: ['props', 'data', 'computed', 'methods', 'setup'],\n    ignorePublicMembers: true,\n  }],\n  'vue/no-unused-refs': [],\n  'vue/no-use-v-else-with-v-for': [],\n  'vue/no-v-text': [],\n  'vue/prefer-prop-type-boolean-first': [],\n  'vue/prefer-separate-static-class': [],\n  'vue/prefer-single-event-payload': [],\n  'vue/prefer-true-attribute-shorthand': [],\n  'vue/require-direct-export': [],\n  'vue/v-for-delimiter-style': ['of'],\n  'vue/v-if-else-key': [],\n  'vue/v-on-handler-style': ['inline'],\n  'vue/v-slot-style': ['shorthand'],\n\n  // Vue 3 migration\n  'vue/no-deprecated-data-object-declaration': [],\n  // 'vue/no-deprecated-destroyed-lifecycle': [], // impossible to fix in Vue 2 (without Composition API)\n  'vue/no-deprecated-dollar-listeners-api': [],\n  'vue/no-deprecated-dollar-scopedslots-api': [],\n  'vue/no-deprecated-events-api': [],\n  'vue/no-deprecated-filter': [],\n  'vue/no-deprecated-functional-template': [],\n  'vue/no-deprecated-html-element-is': [],\n  'vue/no-deprecated-inline-template': [],\n  'vue/no-deprecated-model-definition': [{\n    allowVue3Compat: true,\n  }],\n  'vue/no-deprecated-props-default-this': [],\n  'vue/no-deprecated-router-link-tag-prop': [],\n  'vue/no-deprecated-scope-attribute': [],\n  'vue/no-deprecated-slot-attribute': [],\n  'vue/no-deprecated-slot-scope-attribute': [],\n  'vue/no-deprecated-v-bind-sync': [],\n  'vue/no-deprecated-v-is': [],\n  'vue/no-deprecated-v-on-native-modifier': [],\n  'vue/no-deprecated-v-on-number-modifiers': [],\n  'vue/no-deprecated-vue-config-keycodes': [],\n  'vue/no-expose-after-await': [],\n  'vue/no-lifecycle-after-await': [],\n  'vue/no-negated-condition': [],\n  'vue/no-negated-v-if-condition': [],\n  'vue/no-watch-after-await': [],\n  'vue/prefer-import-from-vue': [],\n  'vue/require-explicit-emits': [],\n  'vue/require-slots-as-functions': [],\n  'vue/require-toggle-inside-transition': [],\n  'vue/v-on-event-hyphenation': [],\n\n  // eslint-plugin-vuejs-accessibility\n  'vuejs-accessibility/no-aria-hidden-on-focusable': [],\n  'vuejs-accessibility/no-role-presentation-on-focusable': [],\n\n  // already included in presets, but needed here because we reduce severity to `warn`\n  'sonarjs/cognitive-complexity': [],\n  'sonarjs/no-nested-functions': [],\n  'sonarjs/regex-complexity': [],\n  'sonarjs/slow-regex': [],\n  'sonarjs/todo-tag': [],\n  'unicorn/no-array-for-each': [],\n  'vue/no-mutating-props': [],\n  'vue/no-v-html': [],\n};\n\nconst vueExtensionRules = {\n  'vue/array-bracket-newline': '@stylistic/array-bracket-newline',\n  'vue/array-bracket-spacing': '@stylistic/array-bracket-spacing',\n  'vue/array-element-newline': '@stylistic/array-element-newline',\n  'vue/arrow-spacing': '@stylistic/arrow-spacing',\n  'vue/block-spacing': '@stylistic/block-spacing',\n  'vue/brace-style': '@stylistic/brace-style',\n  'vue/camelcase': 'camelcase',\n  'vue/comma-dangle': '@stylistic/comma-dangle',\n  'vue/comma-spacing': '@stylistic/comma-spacing',\n  'vue/comma-style': '@stylistic/comma-style',\n  'vue/dot-location': '@stylistic/dot-location',\n  'vue/dot-notation': 'dot-notation',\n  'vue/eqeqeq': 'eqeqeq',\n  'vue/func-call-spacing': '@stylistic/function-call-spacing',\n  'vue/key-spacing': '@stylistic/key-spacing',\n  'vue/keyword-spacing': '@stylistic/keyword-spacing',\n  'vue/max-len': '@stylistic/max-len',\n  'vue/multiline-ternary': '@stylistic/multiline-ternary',\n  'vue/no-console': 'no-console',\n  'vue/no-constant-condition': 'no-constant-condition',\n  'vue/no-empty-pattern': 'no-empty-pattern',\n  'vue/no-extra-parens': '@stylistic/no-extra-parens',\n  'vue/no-implicit-coercion': 'no-implicit-coercion',\n  'vue/no-irregular-whitespace': 'no-irregular-whitespace',\n  'vue/no-loss-of-precision': 'no-loss-of-precision',\n  'vue/no-negated-condition': 'no-negated-condition',\n  'vue/no-restricted-syntax': 'no-restricted-syntax',\n  'vue/no-sparse-arrays': 'no-sparse-arrays',\n  'vue/no-useless-concat': 'no-useless-concat',\n  'vue/object-curly-newline': '@stylistic/object-curly-newline',\n  'vue/object-curly-spacing': '@stylistic/object-curly-spacing',\n  'vue/object-property-newline': '@stylistic/object-property-newline',\n  'vue/object-shorthand': 'object-shorthand',\n  'vue/operator-linebreak': '@stylistic/operator-linebreak',\n  'vue/prefer-template': 'prefer-template',\n  'vue/quote-props': '@stylistic/quote-props',\n  'vue/space-in-parens': '@stylistic/space-in-parens',\n  'vue/space-infix-ops': '@stylistic/space-infix-ops',\n  'vue/space-unary-ops': '@stylistic/space-unary-ops',\n  'vue/template-curly-spacing': '@stylistic/template-curly-spacing',\n};\n\nconst warnRules = new Set([\n  'jsdoc/require-jsdoc',\n  'sonarjs/cognitive-complexity',\n  'sonarjs/no-nested-functions',\n  'sonarjs/regex-complexity',\n  'sonarjs/slow-regex',\n  'sonarjs/todo-tag',\n  'vue/no-mutating-props',\n  'vue/no-v-html',\n]);\n\nconst disabledRules = [\n  'no-console',\n  'jsdoc/empty-tags',\n  'jsdoc/newline-after-description',\n  'jsdoc/no-defaults', // useful for model docs generation\n  'jsdoc/require-description',\n  'jsdoc/require-description-complete-sentence',\n  'jsdoc/tag-lines',\n  'sonarjs/no-os-command-from-path',\n  'sonarjs/no-unsafe-unzip',\n  'sonarjs/os-command',\n  'sonarjs/pseudo-random',\n  'unicorn/consistent-function-scoping',\n  'unicorn/filename-case',\n  'unicorn/no-null',\n  'unicorn/no-process-exit',\n  'unicorn/no-useless-switch-case', // explicit \"useless\" switch chases are documentation\n  'unicorn/no-useless-undefined', // conflicts with `consistent-return`\n  'unicorn/prefer-dom-node-dataset', // grepping ability of `getAttribute('data-foo-bar')` is better than `dataset.fooBar`\n  'unicorn/prefer-global-this',\n  'unicorn/prefer-node-protocol', // not supported by Nuxt yet\n  'vue/multiline-html-element-content-newline',\n  'vue/singleline-html-element-content-newline',\n  'vuejs-accessibility/form-control-has-label',\n  'vuejs-accessibility/label-has-for',\n];\n\nconst getRuleParameters = (ruleOptions) => (Array.isArray(ruleOptions) ? ruleOptions.slice(1) : []);\n\nfor (const [vueRuleName, extendedRuleName] of Object.entries(vueExtensionRules)) {\n  if (enabledRuleParameters[extendedRuleName]) {\n    enabledRuleParameters[vueRuleName] = enabledRuleParameters[extendedRuleName];\n  }\n  else if (eslintJs.configs.recommended.rules[extendedRuleName] && eslintJs.configs.recommended.rules[extendedRuleName] !== 'off') {\n    enabledRuleParameters[vueRuleName] = getRuleParameters(eslintJs.configs.recommended.rules[extendedRuleName]);\n  }\n  else if (stylisticEslintConfig.rules[extendedRuleName] && stylisticEslintConfig.rules[extendedRuleName] !== 'off') {\n    enabledRuleParameters[vueRuleName] = getRuleParameters(stylisticEslintConfig.rules[extendedRuleName]);\n  }\n}\n\nexport default [\n  {\n    ignores: [\n      'package-lock.json',\n      'fixtures/register.json',\n      'server/ofl-secrets.json',\n      '.vscode/',\n      '.nuxt/',\n      'node_modules/',\n      'tmp/',\n    ],\n  },\n  eslintJs.configs.recommended,\n  stylisticEslintConfig,\n  eslintPluginImport.flatConfigs.recommended,\n  eslintPluginJsdoc.configs['flat/recommended-typescript-flavor'],\n  eslintPluginNuxtConfigRecommended,\n  eslintPluginPromise.configs['flat/recommended'],\n  eslintPluginSonarjs.configs.recommended,\n  eslintPluginUnicorn.configs.recommended,\n  ...eslintPluginVue.configs['flat/vue2-recommended-error'],\n  ...eslintPluginVueA11y.configs['flat/recommended'],\n  ...eslintPluginJsoncConfigs['recommended-with-json'], // has to be after `vue`\n  {\n    linterOptions: {\n      reportUnusedDisableDirectives: 'error',\n      reportUnusedInlineConfigs: 'error',\n    },\n    languageOptions: {\n      globals: globals.node,\n      ecmaVersion: 2025,\n      sourceType: 'module',\n    },\n    rules: {\n      ...Object.fromEntries(\n        Object.entries(enabledRuleParameters).map(([ruleName, parameters]) => [\n          ruleName,\n          [warnRules.has(ruleName) ? 'warn' : 'error', ...parameters],\n        ]),\n      ),\n      ...Object.fromEntries(\n        disabledRules.map((ruleName) => [ruleName, 'off']),\n      ),\n    },\n    settings: {\n      jsdoc: {\n        tagNamePreference: {\n          augments: 'extends',\n          class: 'constructor',\n          file: 'fileoverview',\n          fires: 'emits',\n          linkcode: 'link',\n          linkplain: 'link',\n          overview: 'fileoverview',\n        },\n        preferredTypes: {\n          '*': 'any',\n          'array': 'Array',\n          'Boolean': 'boolean',\n          'Number': 'number',\n          'Object': 'object',\n          'String': 'string',\n          '.<>': '<>',\n          'Array<>': '[]',\n          'object<>': 'Record<>',\n          'Object<>': 'Record<>',\n        },\n      },\n    },\n  },\n  ...eslintMarkdown.configs.processor,\n  {\n    files: ['**/*.md/*.js'],\n    rules: {\n      'jsdoc/require-jsdoc': 'off',\n      'import/no-unresolved': 'off',\n    },\n  },\n  {\n    files: ['**/*.cjs', 'server/**.js'],\n    languageOptions: {\n      sourceType: 'script',\n    },\n    rules: {\n      'import/no-commonjs': 'off',\n      'unicorn/prefer-module': 'off',\n      'unicorn/prefer-top-level-await': 'off',\n    },\n  },\n  {\n    files: ['ui/layouts/*.vue', 'ui/pages/**/*.vue'],\n    rules: {\n      'vue/multi-word-component-names': 'off',\n    },\n  },\n  {\n    files: ['fixtures/**/*.json'],\n    rules: {\n      // allow alignment of pixel keys in matrix\n      '@stylistic/no-multi-spaces': ['error', {\n        exceptions: {\n          JSONArrayExpression: true,\n        },\n      }],\n      'jsonc/array-bracket-spacing': 'off',\n\n      'unicorn/prevent-abbreviations': 'off',\n    },\n  },\n  {\n    files: ['.devcontainer/devcontainer.json'],\n    rules: {\n      'jsonc/no-comments': 'off',\n    },\n  },\n  {\n    files: ['tests/*.test.js'],\n    ...eslintPluginVitest.configs.recommended,\n  },\n];\n"
  },
  {
    "path": "fixtures/5star-systems/spica-250m.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Spica 250M\",\n  \"shortName\": \"Spica250M\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-01-23\",\n    \"lastModifyDate\": \"2018-08-09\",\n    \"importPlugin\": {\n      \"plugin\": \"ecue\",\n      \"date\": \"2017-01-23\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.ghl.be/?wpfb_dl=134\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=AY2xw4sXFQs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [427, 459, 373],\n    \"weight\": 18,\n    \"power\": 500,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"Sylvania BA 250/2 GY-9.5\",\n      \"colorTemperature\": 8900\n    },\n    \"lens\": {\n      \"degreesMinMax\": [18, 18]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#9800ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32639,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"530deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32639,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"280deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 249],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"comment\": \"black while moving\",\n          \"speed\": \"fast\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"defaultValue\": 170,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan speed\",\n          \"parameterStart\": \"fast\",\n          \"parameterEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp on\"\n        },\n        {\n          \"dmxRange\": [140, 179],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset\"\n        },\n        {\n          \"dmxRange\": [190, 229],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [84, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [98, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [105, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [112, 118],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [119, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Prism\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 12\"\n        }\n      ]\n    },\n    \"Prism rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 126],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [160, 223],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Reset\",\n        \"Color Wheel\",\n        null,\n        \"Prism\",\n        \"Prism rotation\",\n        \"Gobo Wheel\",\n        \"Gobo rotation\",\n        null,\n        \"Focus\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Reset\",\n        \"Color Wheel\",\n        null,\n        \"Prism\",\n        \"Prism rotation\",\n        \"Gobo Wheel\",\n        \"Gobo rotation\",\n        null,\n        \"Focus\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/abstract/twister-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Twister 4\",\n  \"shortName\": \"Twister4\",\n  \"categories\": [\"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-01-24\",\n    \"lastModifyDate\": \"2022-05-03\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2017-01-24\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.sabretechnology.co.uk/pdfs/allman2.pdf\",\n      \"https://www.sabretechnology.co.uk/pdfs/hptwis.pdf\"\n    ],\n    \"video\": [\"https://www.youtube.com/watch?v=AAx21-IF_zQ\"]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 200, 400],\n    \"weight\": 5,\n    \"power\": 250,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"A1/259\"\n    }\n  },\n  \"wheels\": {\n    \"Color / Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red [Dot Tunnel]\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue [Slash]\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green [Segment]\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow [Triangle]\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan [Tunnel]\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange [Bubbles]\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink [Stars]\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Multicolor [Quadrant]\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [12, 112],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [113, 140],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [141, 244],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Color / Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"menuClick\": \"start\"\n        },\n        {\n          \"dmxRange\": [10, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [26, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [43, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [59, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [75, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [91, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [108, 123],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [124, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [140, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [156, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [173, 188],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [189, 220],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [221, 237],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [238, 253],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"menuClick\": \"start\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"menuClick\": \"start\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 23],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [24, 225],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1 CE (2ch)\",\n      \"shortName\": \"1CE-2ch\",\n      \"channels\": [\n        \"Rotation\",\n        \"Color / Gobo Wheel\"\n      ]\n    },\n    {\n      \"name\": \"HP (3ch)\",\n      \"shortName\": \"HP-3ch\",\n      \"channels\": [\n        \"Rotation\",\n        \"Color / Gobo Wheel\",\n        \"Shutter\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/acoustic-control/par-180-cob-3in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PAR 180 COB 3in1\",\n  \"shortName\": \"PAR180\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Sergio Collantes\"],\n    \"createDate\": \"2019-07-31\",\n    \"lastModifyDate\": \"2019-07-31\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/drive/folders/1MNU9qpVMQ3880Og8qXIOpQl60UShyjXo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [220, 220, 90],\n    \"weight\": 1.5,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3× 30W COB RGB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [80, 80]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual Mode\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Activate\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Color\"\n        }\n      ]\n    },\n    \"FX Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Mode\",\n        \"FX Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/adb/alc4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ALC4\",\n  \"shortName\": \"ADBALC4\",\n  \"categories\": [\"Blinder\", \"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"ameisso\"],\n    \"createDate\": \"2018-02-19\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/983476/Adb-Alc4.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [496, 268, 182],\n    \"weight\": 10,\n    \"power\": 200,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 4000\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"4\", \"3\", \"2\", \"1\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": [\"1\", \"2\", \"3\", \"4\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Master\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature $pixelKey (Linear)\": {\n      \"name\": \"Color Temperature $pixelKey\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB Mode\"\n        },\n        {\n          \"dmxRange\": [51, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2700K\",\n          \"colorTemperatureEnd\": \"6500K\"\n        }\n      ]\n    },\n    \"Color Temperature $pixelKey (7 Presets)\": {\n      \"name\": \"Color Temperature $pixelKey\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB Mode\"\n        },\n        {\n          \"dmxRange\": [77, 101],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [102, 127],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"dmxRange\": [128, 152],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [153, 178],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [179, 203],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [204, 229],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        }\n      ]\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard Linear\",\n      \"shortName\": \"std-lin\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Color Temperature Master (Linear)\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"Matrix Linear\",\n      \"shortName\": \"matrix-lin\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Color Temperature $pixelKey (Linear)\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Extended Linear\",\n      \"shortName\": \"ext-lin\",\n      \"channels\": [\n        \"Master\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Color Temperature $pixelKey (Linear)\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Standard 7 Presets\",\n      \"shortName\": \"std-presets\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Color Temperature Master (7 Presets)\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"Matrix 7 Presets\",\n      \"shortName\": \"matrix-presets\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Color Temperature $pixelKey (7 Presets)\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Extended 7 Presets\",\n      \"shortName\": \"ext-presets\",\n      \"channels\": [\n        \"Master\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Color Temperature $pixelKey (7 Presets)\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/adb/europe-105.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Europe 105\",\n  \"shortName\": \"ADBEurope105\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"ameisso\"],\n    \"createDate\": \"2018-02-15\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"comment\": \"Only controllable via dimmer pack\",\n  \"links\": {\n    \"manual\": [\"https://www.adbstagelight.com/wp-content/uploads/2017/04/DS5153-E-Europe105-data-sheet.pdf\"]\n  },\n  \"physical\": {\n    \"bulb\": {\n      \"type\": \"Tungsten halogen\",\n      \"colorTemperature\": 3200\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 1,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"DW 105 1000W\",\n      \"shortName\": \"DW105-1k\",\n      \"physical\": {\n        \"dimensions\": [340, 420, 710],\n        \"weight\": 14,\n        \"power\": 1000,\n        \"bulb\": {\n          \"lumens\": 26000\n        },\n        \"lens\": {\n          \"name\": \"DS 105\",\n          \"degreesMinMax\": [15, 38]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DW 105 1200W\",\n      \"shortName\": \"DW105-1.2k\",\n      \"physical\": {\n        \"dimensions\": [340, 420, 710],\n        \"weight\": 14,\n        \"power\": 1200,\n        \"bulb\": {\n          \"lumens\": 30000\n        },\n        \"lens\": {\n          \"name\": \"DS 105\",\n          \"degreesMinMax\": [15, 38]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DVW 105 1000W\",\n      \"shortName\": \"DVW105-1k\",\n      \"physical\": {\n        \"dimensions\": [340, 420, 600],\n        \"weight\": 13.5,\n        \"power\": 1000,\n        \"bulb\": {\n          \"lumens\": 26000\n        },\n        \"lens\": {\n          \"name\": \"DVW 105\",\n          \"degreesMinMax\": [38, 57]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DVW 105 1200W\",\n      \"shortName\": \"DVW105-1.2k\",\n      \"physical\": {\n        \"dimensions\": [340, 420, 600],\n        \"weight\": 13.5,\n        \"power\": 1200,\n        \"bulb\": {\n          \"lumens\": 30000\n        },\n        \"lens\": {\n          \"name\": \"DVW 105\",\n          \"degreesMinMax\": [38, 57]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DS 105 1000W\",\n      \"shortName\": \"DS105-1k\",\n      \"physical\": {\n        \"dimensions\": [340, 420, 710],\n        \"weight\": 14,\n        \"power\": 1000,\n        \"bulb\": {\n          \"lumens\": 26000\n        },\n        \"lens\": {\n          \"name\": \"DS 105\",\n          \"degreesMinMax\": [15, 38]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DS 105 1200W\",\n      \"shortName\": \"DS105-1.2k\",\n      \"physical\": {\n        \"dimensions\": [340, 420, 710],\n        \"weight\": 14,\n        \"power\": 1200,\n        \"bulb\": {\n          \"lumens\": 30000\n        },\n        \"lens\": {\n          \"name\": \"DS 105\",\n          \"degreesMinMax\": [15, 38]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DSN 105 1000W\",\n      \"shortName\": \"DSN105-1k\",\n      \"physical\": {\n        \"dimensions\": [340, 420, 790],\n        \"weight\": 15.1,\n        \"power\": 1000,\n        \"bulb\": {\n          \"lumens\": 26000\n        },\n        \"lens\": {\n          \"name\": \"DSN 105\",\n          \"degreesMinMax\": [11, 23]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DSN 105 1200W\",\n      \"shortName\": \"DSN105-1.2k\",\n      \"physical\": {\n        \"dimensions\": [340, 420, 790],\n        \"weight\": 15.1,\n        \"power\": 1200,\n        \"bulb\": {\n          \"lumens\": 30000\n        },\n        \"lens\": {\n          \"name\": \"DSN 105\",\n          \"degreesMinMax\": [11, 23]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DN 105 1000W\",\n      \"shortName\": \"DN105-1k\",\n      \"physical\": {\n        \"dimensions\": [360, 445, 920],\n        \"weight\": 18.4,\n        \"power\": 1000,\n        \"bulb\": {\n          \"lumens\": 26000\n        },\n        \"lens\": {\n          \"name\": \"DN 105\",\n          \"degreesMinMax\": [9, 20]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"DN 105 1200W\",\n      \"shortName\": \"DN105-1.2k\",\n      \"physical\": {\n        \"dimensions\": [360, 445, 920],\n        \"weight\": 18.4,\n        \"power\": 1200,\n        \"bulb\": {\n          \"lumens\": 30000\n        },\n        \"lens\": {\n          \"name\": \"DN 105\",\n          \"degreesMinMax\": [9, 20]\n        }\n      },\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/adb/warp-m.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"WARP/M\",\n  \"shortName\": \"ADBWarpM\",\n  \"categories\": [\"Moving Head\"],\n  \"meta\": {\n    \"authors\": [\"ameisso\"],\n    \"createDate\": \"2018-03-29\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"comment\": \"Fully MOTORISED Zoom Profile for the Theatre, the Opera House, the Concert Hall\",\n  \"links\": {\n    \"manual\": [\"https://www.adbstagelight.com/wp-content/uploads/2017/05/M5083-E-user-manual-WARP-M.pdf\"]\n  },\n  \"physical\": {\n    \"dimensions\": [549, 695, 448],\n    \"weight\": 32,\n    \"power\": 900,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"halogen\",\n      \"colorTemperature\": 3200\n    }\n  },\n  \"availableChannels\": {\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Park\"\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Online\"\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stealth Mode\"\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Quiet Mode\"\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fast mode\"\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all Shutters\"\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Gobo 1\"\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo 2/iris\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Zoom\"\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Focus\"\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan\"\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Tilt\"\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Calibration lens\"\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Calibration of Shutters\"\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Calibration of Pan/Tilt\"\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Calibration of Iris/Gobo\"\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan invert On\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan invert Off\"\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt invert On\"\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt invert Off\"\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt swap On\"\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt swap Off\"\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display On\"\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Off\"\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Factory default setting\"\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"User setting 1\"\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"User setting 2\"\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"Maintenance\",\n          \"comment\": \"User setting 3\"\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX address setting\"\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Accessory change\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo Mode indexed\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo Mode indexed and Endless rotation\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Arm\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"400deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"275deg\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\",\n        \"helpWanted\": \"Correct direction?\"\n      }\n    },\n    \"Focus\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\",\n        \"helpWanted\": \"Correct direction?\"\n      }\n    },\n    \"Shutter A Rotation\": {\n      \"fineChannelAliases\": [\"Shutter A Rotation fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"BladeRotation\",\n        \"blade\": 1,\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"720deg\"\n      }\n    },\n    \"Shutter A Insertion\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Shutter B Rotation\": {\n      \"fineChannelAliases\": [\"Shutter B Rotation fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"BladeRotation\",\n        \"blade\": 2,\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"720deg\"\n      }\n    },\n    \"Shutter B Insertion\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Shutter C Rotation\": {\n      \"fineChannelAliases\": [\"Shutter C Rotation fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"BladeRotation\",\n        \"blade\": 3,\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"720deg\"\n      }\n    },\n    \"Shutter C Insertion\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 3,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Shutter D Rotation\": {\n      \"fineChannelAliases\": [\"Shutter D Rotation fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"BladeRotation\",\n        \"blade\": 4,\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"720deg\"\n      }\n    },\n    \"Shutter D Insertion\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 4,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Shutters all rotation offset\": {\n      \"fineChannelAliases\": [\"Shutters all rotation offset fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"BladeSystemRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"720deg\"\n      }\n    },\n    \"Gobo 1 rotation\": {\n      \"fineChannelAliases\": [\"Gobo 1 rotation fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Iris\": {\n      \"fineChannelAliases\": [\"Iris fine\"],\n      \"capability\": {\n        \"type\": \"Iris\",\n        \"openPercentStart\": \"open\",\n        \"openPercentEnd\": \"closed\"\n      }\n    },\n    \"External dimmer (optional)\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"External DMX output 1\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"External DMX output 2\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"External DMX output 3\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"External DMX output 4\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"External DMX output 5\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"External DMX output 6\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"External DMX output 7\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"External DMX output 8\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-30\",\n      \"shortName\": \"warpm1230\",\n      \"physical\": {\n        \"lens\": {\n          \"name\": \"WARP/M/12-30\",\n          \"degreesMinMax\": [12, 30]\n        }\n      },\n      \"channels\": [\n        \"Control\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Zoom\",\n        \"Focus\",\n        \"Shutter A Rotation\",\n        \"Shutter A Rotation fine\",\n        \"Shutter A Insertion\",\n        \"Shutter B Rotation\",\n        \"Shutter B Rotation fine\",\n        \"Shutter B Insertion\",\n        \"Shutter C Rotation\",\n        \"Shutter C Rotation fine\",\n        \"Shutter C Insertion\",\n        \"Shutter D Rotation\",\n        \"Shutter D Rotation fine\",\n        \"Shutter D Insertion\",\n        \"Shutters all rotation offset\",\n        \"Shutters all rotation offset fine\",\n        \"Gobo 1 rotation\",\n        \"Gobo 1 rotation fine\",\n        \"Iris\",\n        \"Iris fine\",\n        \"External dimmer (optional)\",\n        \"External DMX output 1\",\n        \"External DMX output 2\",\n        \"External DMX output 3\",\n        \"External DMX output 4\",\n        \"External DMX output 5\",\n        \"External DMX output 6\",\n        \"External DMX output 7\",\n        \"External DMX output 8\"\n      ]\n    },\n    {\n      \"name\": \"22-50\",\n      \"shortName\": \"warpm2250\",\n      \"physical\": {\n        \"lens\": {\n          \"name\": \"WARP/M/22-50\",\n          \"degreesMinMax\": [22, 50]\n        }\n      },\n      \"channels\": [\n        \"Control\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Zoom\",\n        \"Focus\",\n        \"Shutter A Rotation\",\n        \"Shutter A Rotation fine\",\n        \"Shutter A Insertion\",\n        \"Shutter B Rotation\",\n        \"Shutter B Rotation fine\",\n        \"Shutter B Insertion\",\n        \"Shutter C Rotation\",\n        \"Shutter C Rotation fine\",\n        \"Shutter C Insertion\",\n        \"Shutter D Rotation\",\n        \"Shutter D Rotation fine\",\n        \"Shutter D Insertion\",\n        \"Shutters all rotation offset\",\n        \"Shutters all rotation offset fine\",\n        \"Gobo 1 rotation\",\n        \"Gobo 1 rotation fine\",\n        \"Iris\",\n        \"Iris fine\",\n        \"External dimmer (optional)\",\n        \"External DMX output 1\",\n        \"External DMX output 2\",\n        \"External DMX output 3\",\n        \"External DMX output 4\",\n        \"External DMX output 5\",\n        \"External DMX output 6\",\n        \"External DMX output 7\",\n        \"External DMX output 8\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/afx/lmh460z.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LMH460Z\",\n  \"shortName\": \"LMH460Z\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Folson_dev\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-03-22\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"comment\": \"Wash Zoom LED\",\n  \"links\": {\n    \"manual\": [\n      \"https://manual-hub.com/manuals/afx-lmh460z-01-pdf-manual/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Y6BBSuRVWwQ\",\n      \"https://www.youtube.com/watch?v=vEnjSQS7QY0\",\n      \"https://www.youtube.com/watch?v=-POl9ZfaeQs\"\n    ]\n  },\n  \"helpWanted\": \"Please provide a manual.\",\n  \"physical\": {\n    \"dimensions\": [350, 400, 260],\n    \"weight\": 9,\n    \"power\": 400,\n    \"powerConnectors\": {\n      \"powerCON\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"36x 10W RGBW LED\",\n      \"lumens\": 451.53\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"280deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"0%\",\n        \"speedEnd\": \"100%\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [7, 65],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [66, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [70, 128],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [132, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [196, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Dimmer 0-100\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"RGB Color Change\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"helpWanted\": \"At which DMX values is an effect activated?\"\n      }\n    },\n    \"Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 80],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [81, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 110],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [111, 125],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [126, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic program\"\n        },\n        {\n          \"dmxRange\": [176, 190],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [191, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound activated program\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Pan/Tilt Reversion\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"Pan Tilt Forward\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Pan Reverse\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Generic\",\n          \"comment\": \"Pan Tilt Reverse\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Tilt Reverse\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"15deg\",\n        \"angleEnd\": \"60deg\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Default\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"RGB Color Change\",\n        \"Functions\",\n        \"Pan/Tilt Reversion\",\n        \"Zoom\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/alien-pro/alien-s.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Alien S\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Yéred Zabdiel\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-01-29\",\n    \"lastModifyDate\": \"2022-01-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://alienpro.com.mx/wp-content/uploads/Manual-Bar-Alien-S.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=iuyEvc5mtj4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1070, 65, 88],\n    \"weight\": 2.6,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"240× 10mm LED (96 red, 72 green, 72 blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [8, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/4\": [\"1\", \"2\"],\n      \"2/4\": [\"3\", \"4\"],\n      \"3/4\": [\"5\", \"6\"],\n      \"4/4\": [\"7\", \"8\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Flash Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 01\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 02\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 03\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 04\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 05\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 06\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 07\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 08\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 09\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 21\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel d-P1\",\n      \"shortName\": \"d-P1\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"4-channel d-P2\",\n      \"shortName\": \"d-P2\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"14-channel d-P3\",\n      \"shortName\": \"d-P3\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"1/4\",\n            \"2/4\",\n            \"3/4\",\n            \"4/4\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Flash Speed\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"26-channel d-P4\",\n      \"shortName\": \"d-P4\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Flash Speed\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"2-channel d-P5\",\n      \"shortName\": \"d-P5\",\n      \"channels\": [\n        \"Macros\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"7-channel d-P6\",\n      \"shortName\": \"d-P6\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Macros\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Flash Speed\",\n        \"Master Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/12p-hex-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"12P Hex IP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-05-13\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/11451/ADJ%2012P%20Hex%20IP%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/12p-hex-ip\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=NOuPRgtXDfg\",\n      \"https://www.youtube.com/watch?v=K5_n1dv_9Ps\",\n      \"https://www.youtube.com/watch?v=IHHHL4Xzoy8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [298, 199.5, 264],\n    \"weight\": 4.7,\n    \"power\": 104.5,\n    \"DMXconnector\": \"5-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"12× 12W RGBWA+UV LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"colors\": [\"#88fff1\"]\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\",\n          \"colors\": [\"#88ffc1\"]\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\",\n          \"colors\": [\"#84ff9c\"]\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\",\n          \"colors\": [\"#a2ff8b\"]\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\",\n          \"colors\": [\"#bdff84\"]\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\",\n          \"colors\": [\"#e9ff8b\"]\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\",\n          \"colors\": [\"#fff784\"]\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\",\n          \"colors\": [\"#ffd880\"]\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\",\n          \"colors\": [\"#ffc184\"]\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\",\n          \"colors\": [\"#ffa480\"]\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\",\n          \"colors\": [\"#ff9082\"]\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\",\n          \"colors\": [\"#ff7c80\"]\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\",\n          \"colors\": [\"#ff8bae\"]\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\",\n          \"colors\": [\"#ff97d0\"]\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\",\n          \"colors\": [\"#ff9af3\"]\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\",\n          \"colors\": [\"#f497ff\"]\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\",\n          \"colors\": [\"#d890ff\"]\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\",\n          \"colors\": [\"#bb94ff\"]\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\",\n          \"colors\": [\"#9484ff\"]\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\",\n          \"colors\": [\"#8494ff\"]\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\",\n          \"colors\": [\"#76b1ff\"]\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\",\n          \"colors\": [\"#84d5ff\"]\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\",\n          \"colors\": [\"#84f0ff\"]\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\",\n          \"colors\": [\"#cdffc6\"]\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\",\n          \"colors\": [\"#fffdcc\"]\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\",\n          \"colors\": [\"#ffd6c8\"]\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\",\n          \"colors\": [\"#ffc1db\"]\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\",\n          \"colors\": [\"#ffc8fd\"]\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\",\n          \"colors\": [\"#c8c1ff\"]\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\",\n          \"colors\": [\"#adc1ff\"]\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\",\n          \"colors\": [\"#c1d2ff\"]\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32 = Full White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 33\",\n          \"colors\": [\"#ffce8f\"]\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 34\",\n          \"colors\": [\"#feb199\"]\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 35\",\n          \"colors\": [\"#fec08a\"]\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 36\",\n          \"colors\": [\"#fea562\"]\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 37\",\n          \"colors\": [\"#fe7900\"]\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 38\",\n          \"colors\": [\"#b01100\"]\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 39\",\n          \"colors\": [\"#60000b\"]\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 40\",\n          \"colors\": [\"#ea8bab\"]\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 41\",\n          \"colors\": [\"#a10561\"]\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 42\",\n          \"colors\": [\"#af4dad\"]\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 43\",\n          \"colors\": [\"#7782c7\"]\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 44\",\n          \"colors\": [\"#93a4d4\"]\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 45\",\n          \"colors\": [\"#5802a3\"]\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 46\",\n          \"colors\": [\"#002656\"]\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 47\",\n          \"colors\": [\"#008ed0\"]\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 48\",\n          \"colors\": [\"#3494d1\"]\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 49\",\n          \"colors\": [\"#002e23\"]\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 50\",\n          \"colors\": [\"#086bde\"]\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 51\",\n          \"colors\": [\"#6b9ce7\"]\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 52\",\n          \"colors\": [\"#a5c6f7\"]\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 53\",\n          \"colors\": [\"#005373\"]\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 54\",\n          \"colors\": [\"#0061a6\"]\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 55\",\n          \"colors\": [\"#0164a7\"]\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 56\",\n          \"colors\": [\"#002856\"]\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 57\",\n          \"colors\": [\"#d1dbb6\"]\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 58\",\n          \"colors\": [\"#2aa555\"]\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 59 = Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 60 = Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 61 = Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 62 = White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 63 = Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"long\",\n        \"durationEnd\": \"short\"\n      }\n    },\n    \"Dimmer Modes\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Presets\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/18p-hex-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"18P HEX IP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-03-27\",\n    \"lastModifyDate\": \"2022-03-27\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/11452/ADJ%2018P%20Hex%20IP%20-%20User%20Manual%20.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/18p-hex-ip\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=NOuPRgtXDfg\",\n      \"https://www.youtube.com/watch?v=K5_n1dv_9Ps\",\n      \"https://www.youtube.com/watch?v=IHHHL4Xzoy8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [336, 233, 279],\n    \"weight\": 6.1,\n    \"power\": 155.5,\n    \"DMXconnector\": \"5-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"18× 12W RGBAW+UV LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"colors\": [\"#88fff1\"]\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\",\n          \"colors\": [\"#88ffc1\"]\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\",\n          \"colors\": [\"#84ff9c\"]\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\",\n          \"colors\": [\"#a2ff8b\"]\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\",\n          \"colors\": [\"#bdff84\"]\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\",\n          \"colors\": [\"#e9ff8b\"]\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\",\n          \"colors\": [\"#fff784\"]\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\",\n          \"colors\": [\"#ffd880\"]\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\",\n          \"colors\": [\"#ffc184\"]\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\",\n          \"colors\": [\"#ffa480\"]\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\",\n          \"colors\": [\"#ff9082\"]\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\",\n          \"colors\": [\"#ff7c80\"]\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\",\n          \"colors\": [\"#ff8bae\"]\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\",\n          \"colors\": [\"#ff97d0\"]\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\",\n          \"colors\": [\"#ff9af3\"]\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\",\n          \"colors\": [\"#f497ff\"]\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\",\n          \"colors\": [\"#d890ff\"]\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\",\n          \"colors\": [\"#bb94ff\"]\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\",\n          \"colors\": [\"#9484ff\"]\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\",\n          \"colors\": [\"#8494ff\"]\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\",\n          \"colors\": [\"#76b1ff\"]\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\",\n          \"colors\": [\"#84d5ff\"]\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\",\n          \"colors\": [\"#84f0ff\"]\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\",\n          \"colors\": [\"#cdffc6\"]\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\",\n          \"colors\": [\"#fffdcc\"]\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\",\n          \"colors\": [\"#ffd6c8\"]\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\",\n          \"colors\": [\"#ffc1db\"]\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\",\n          \"colors\": [\"#ffc8fd\"]\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\",\n          \"colors\": [\"#c8c1ff\"]\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\",\n          \"colors\": [\"#adc1ff\"]\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\",\n          \"colors\": [\"#c1d2ff\"]\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32 = Full White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 33\",\n          \"colors\": [\"#ffce8f\"]\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 34\",\n          \"colors\": [\"#feb199\"]\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 35\",\n          \"colors\": [\"#fec08a\"]\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 36\",\n          \"colors\": [\"#fea562\"]\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 37\",\n          \"colors\": [\"#fe7900\"]\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 38\",\n          \"colors\": [\"#b01100\"]\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 39\",\n          \"colors\": [\"#60000b\"]\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 40\",\n          \"colors\": [\"#ea8bab\"]\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 41\",\n          \"colors\": [\"#a10561\"]\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 42\",\n          \"colors\": [\"#af4dad\"]\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 43\",\n          \"colors\": [\"#7782c7\"]\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 44\",\n          \"colors\": [\"#93a4d4\"]\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 45\",\n          \"colors\": [\"#5802a3\"]\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 46\",\n          \"colors\": [\"#002656\"]\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 47\",\n          \"colors\": [\"#008ed0\"]\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 48\",\n          \"colors\": [\"#3494d1\"]\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 49\",\n          \"colors\": [\"#002e23\"]\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 50\",\n          \"colors\": [\"#086bde\"]\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 51\",\n          \"colors\": [\"#6b9ce7\"]\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 52\",\n          \"colors\": [\"#a5c6f7\"]\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 53\",\n          \"colors\": [\"#005373\"]\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 54\",\n          \"colors\": [\"#0061a6\"]\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 55\",\n          \"colors\": [\"#0164a7\"]\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 56\",\n          \"colors\": [\"#002856\"]\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 57\",\n          \"colors\": [\"#d1dbb6\"]\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 58\",\n          \"colors\": [\"#2aa555\"]\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 59 = Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 60 = Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 61 = Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 62 = White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 63 = Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"long\",\n        \"durationEnd\": \"short\"\n      }\n    },\n    \"Dimmer Modes\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Presets\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/7p-hex-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"7P HEX IP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-03-22\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"comment\": \"The webpage claims \\\"6, 6+, 9, 9+, 10, & 12-channel\\\" modes, but this seems to be completely false.\",\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/11448/ADJ%207P%20Hex%20IP%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/7p-hex-ip\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=NOuPRgtXDfg\",\n      \"https://www.youtube.com/watch?v=K5_n1dv_9Ps\",\n      \"https://www.youtube.com/watch?v=IHHHL4Xzoy8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [256, 161.7, 232.5],\n    \"weight\": 3.3,\n    \"power\": 63.1,\n    \"DMXconnector\": \"5-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"7× 12W RGBWA+UV LED\",\n      \"lumens\": 1650\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"colors\": [\"#88fff1\"]\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\",\n          \"colors\": [\"#88ffc1\"]\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\",\n          \"colors\": [\"#84ff9c\"]\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\",\n          \"colors\": [\"#a2ff8b\"]\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\",\n          \"colors\": [\"#bdff84\"]\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\",\n          \"colors\": [\"#e9ff8b\"]\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\",\n          \"colors\": [\"#fff784\"]\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\",\n          \"colors\": [\"#ffd880\"]\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\",\n          \"colors\": [\"#ffc184\"]\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\",\n          \"colors\": [\"#ffa480\"]\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\",\n          \"colors\": [\"#ff9082\"]\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\",\n          \"colors\": [\"#ff7c80\"]\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\",\n          \"colors\": [\"#ff8bae\"]\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\",\n          \"colors\": [\"#ff97d0\"]\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\",\n          \"colors\": [\"#ff9af3\"]\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\",\n          \"colors\": [\"#f497ff\"]\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\",\n          \"colors\": [\"#d890ff\"]\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\",\n          \"colors\": [\"#bb94ff\"]\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\",\n          \"colors\": [\"#9484ff\"]\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\",\n          \"colors\": [\"#8494ff\"]\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\",\n          \"colors\": [\"#76b1ff\"]\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\",\n          \"colors\": [\"#84d5ff\"]\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\",\n          \"colors\": [\"#84f0ff\"]\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\",\n          \"colors\": [\"#cdffc6\"]\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\",\n          \"colors\": [\"#fffdcc\"]\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\",\n          \"colors\": [\"#ffd6c8\"]\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\",\n          \"colors\": [\"#ffc1db\"]\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\",\n          \"colors\": [\"#ffc8fd\"]\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\",\n          \"colors\": [\"#c8c1ff\"]\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\",\n          \"colors\": [\"#adc1ff\"]\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\",\n          \"colors\": [\"#c1d2ff\"]\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32 = Full White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 33\",\n          \"colors\": [\"#ffce8f\"]\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 34\",\n          \"colors\": [\"#feb199\"]\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 35\",\n          \"colors\": [\"#fec08a\"]\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 36\",\n          \"colors\": [\"#fea562\"]\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 37\",\n          \"colors\": [\"#fe7900\"]\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 38\",\n          \"colors\": [\"#b01100\"]\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 39\",\n          \"colors\": [\"#60000b\"]\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 40\",\n          \"colors\": [\"#ea8bab\"]\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 41\",\n          \"colors\": [\"#a10561\"]\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 42\",\n          \"colors\": [\"#af4dad\"]\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 43\",\n          \"colors\": [\"#7782c7\"]\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 44\",\n          \"colors\": [\"#93a4d4\"]\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 45\",\n          \"colors\": [\"#5802a3\"]\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 46\",\n          \"colors\": [\"#002656\"]\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 47\",\n          \"colors\": [\"#008ed0\"]\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 48\",\n          \"colors\": [\"#3494d1\"]\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 49\",\n          \"colors\": [\"#002e23\"]\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 50\",\n          \"colors\": [\"#086bde\"]\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 51\",\n          \"colors\": [\"#6b9ce7\"]\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 52\",\n          \"colors\": [\"#a5c6f7\"]\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 53\",\n          \"colors\": [\"#005373\"]\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 54\",\n          \"colors\": [\"#0061a6\"]\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 55\",\n          \"colors\": [\"#0164a7\"]\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 56\",\n          \"colors\": [\"#002856\"]\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 57\",\n          \"colors\": [\"#d1dbb6\"]\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 58\",\n          \"colors\": [\"#2aa555\"]\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 59 = Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 60 = Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 61 = Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 62 = White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 63 = Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"long\",\n        \"durationEnd\": \"short\"\n      }\n    },\n    \"Dimmer Modes\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Presets\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/auto-spot-150.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Auto Spot 150\",\n  \"shortName\": \"ADJAutoSpot150\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-01-18\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"comment\": \"The different modes refer to the 'Color Mode' setting: no (Full Color) or SC (Split Color)\",\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/7650/Auto%20Spot%20150.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [295, 451, 373],\n    \"weight\": 13,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LL-HTI150 discharge lamp\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#aaddff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffaaaa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#aaffaa\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 120],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [135, 245],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Split Colors\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [21, 26],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [27, 33],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [34, 40],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [41, 46],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [47, 53],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [54, 60],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 66],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [67, 73],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [74, 80],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [81, 87],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [88, 93],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [94, 100],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [101, 107],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [108, 113],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [114, 120],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [121, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Shutter / Dimmer\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [5, 131],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"off\",\n          \"brightnessEnd\": \"bright\"\n        },\n        {\n          \"dmxRange\": [132, 252],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Full Colors\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [13, 25],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [26, 38],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [39, 51],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [52, 63],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [64, 76],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [77, 89],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [90, 102],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [103, 115],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [116, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Full Color\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Full Colors\",\n        \"Shutter / Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Split Color\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Split Colors\",\n        \"Shutter / Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/boom-box-fx2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Boom Box Fx2\",\n  \"shortName\": \"ADJBoomBoxFx2\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-11-17\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"http://adjmedia.s3-website-eu-west-1.amazonaws.com/manuals/boom_box_fx2.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=E3-njFee518\",\n      \"https://www.youtube.com/watch?v=DXzJ8QSDcmw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [634, 319, 232],\n    \"weight\": 8,\n    \"power\": 62,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"8x3W LEDs, 8x1W LEDs, 8x10W RGBW LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Show mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 1\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 2\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 3\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 4\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 5\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 6\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 7\"\n        },\n        {\n          \"dmxRange\": [140, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 8\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 9\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 0\"\n        }\n      ]\n    },\n    \"Show speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 139],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [140, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Center LED\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macros\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Red Laser\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open\"\n        }\n      ]\n    },\n    \"Green Laser\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open\"\n        }\n      ]\n    },\n    \"Laser Patterns\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Laser patterns\"\n      }\n    },\n    \"Red Beam\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green Beam\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue Beam\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White Beam\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Beam Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Beam Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"comment\": \"indexing\",\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Beam Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red Gobo Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open\"\n        }\n      ]\n    },\n    \"Green Gobo Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open\"\n        }\n      ]\n    },\n    \"Blue Gobo Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open\"\n        }\n      ]\n    },\n    \"White Gobo Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"comment\": \"indexing\",\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Show mode\",\n        \"Show speed\",\n        \"Special Functions\"\n      ]\n    },\n    {\n      \"name\": \"19-channel\",\n      \"shortName\": \"19ch\",\n      \"channels\": [\n        \"Center LED\",\n        \"Red Laser\",\n        \"Green Laser\",\n        \"Laser Patterns\",\n        \"Red Beam\",\n        \"Green Beam\",\n        \"Blue Beam\",\n        \"White Beam\",\n        \"Beam Strobe\",\n        \"Beam Dimmer\",\n        \"Beam Rotation\",\n        \"Red Gobo Effect\",\n        \"Green Gobo Effect\",\n        \"Blue Gobo Effect\",\n        \"White Gobo Effect\",\n        \"Gobo Rotation\",\n        \"Show mode\",\n        \"Show speed\",\n        \"Special Functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/cob-cannon-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"COB Cannon Wash\",\n  \"categories\": [\"Color Changer\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Travis Versher\"],\n    \"createDate\": \"2019-07-18\",\n    \"lastModifyDate\": \"2019-07-18\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/8775/COB%20CANNON%20WASH%20-%20USER%20MANUAL.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/cob-cannon-wash\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [415, 245, 192],\n    \"weight\": 4.1,\n    \"power\": 132,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"150W RGBA COB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [80, 80]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Black\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\",\n          \"colors\": [\"#82ffbd\"]\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\",\n          \"colors\": [\"#82ff85\"]\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\",\n          \"colors\": [\"#7eff5b\"]\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\",\n          \"colors\": [\"#a1ff43\"]\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\",\n          \"colors\": [\"#c1ff3f\"]\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\",\n          \"colors\": [\"#f6ff43\"]\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\",\n          \"colors\": [\"#ffe73b\"]\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\",\n          \"colors\": [\"#ffc639\"]\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\",\n          \"colors\": [\"#ffac3b\"]\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\",\n          \"colors\": [\"#ff8c39\"]\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\",\n          \"colors\": [\"#ff763c\"]\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\",\n          \"colors\": [\"#ff613c\"]\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\",\n          \"colors\": [\"#ff6e65\"]\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\",\n          \"colors\": [\"#ff7785\"]\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\",\n          \"colors\": [\"#ff7aab\"]\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\",\n          \"colors\": [\"#ff7dc4\"]\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\",\n          \"colors\": [\"#ff89e6\"]\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\",\n          \"colors\": [\"#f09dff\"]\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\",\n          \"colors\": [\"#b187ff\"]\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\",\n          \"colors\": [\"#9a9eff\"]\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\",\n          \"colors\": [\"#86c6ff\"]\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\",\n          \"colors\": [\"#9afdff\"]\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\",\n          \"colors\": [\"#87ffdf\"]\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\",\n          \"colors\": [\"#d4ff65\"]\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\",\n          \"colors\": [\"#ffe560\"]\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\",\n          \"colors\": [\"#ffb55d\"]\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\",\n          \"colors\": [\"#ff9d79\"]\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\",\n          \"colors\": [\"#ffa39f\"]\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\",\n          \"colors\": [\"#ffd5e1\"]\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\",\n          \"colors\": [\"#ffd5e1\"]\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32\",\n          \"colors\": [\"#fffcec\"]\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 33\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 34\",\n          \"colors\": [\"#ffce8f\"]\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 35\",\n          \"colors\": [\"#feb199\"]\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 36\",\n          \"colors\": [\"#fec08a\"]\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 37\",\n          \"colors\": [\"#fea562\"]\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 38\",\n          \"colors\": [\"#fe7900\"]\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 39\",\n          \"colors\": [\"#b01100\"]\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 40\",\n          \"colors\": [\"#60000b\"]\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 41\",\n          \"colors\": [\"#ea8bab\"]\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 42\",\n          \"colors\": [\"#e00561\"]\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 43\",\n          \"colors\": [\"#af4dad\"]\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 44\",\n          \"colors\": [\"#7782c7\"]\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 45\",\n          \"colors\": [\"#93a4d4\"]\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 46\",\n          \"colors\": [\"#5802a3\"]\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 47\",\n          \"colors\": [\"#002656\"]\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 48\",\n          \"colors\": [\"#008ed0\"]\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 49\",\n          \"colors\": [\"#3494d1\"]\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 50\",\n          \"colors\": [\"#0186c9\"]\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 51\",\n          \"colors\": [\"#0091d4\"]\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 52\",\n          \"colors\": [\"#0079c0\"]\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 53\",\n          \"colors\": [\"#0081b8\"]\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 54\",\n          \"colors\": [\"#005373\"]\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 55\",\n          \"colors\": [\"#0061a6\"]\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 56\",\n          \"colors\": [\"#0164a7\"]\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 57\",\n          \"colors\": [\"#002856\"]\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 58\",\n          \"colors\": [\"#d1dbb6\"]\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 59\",\n          \"colors\": [\"#2aa555\"]\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 60\",\n          \"colors\": [\"#002e23\"]\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 61\",\n          \"colors\": [\"#086bde\"]\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 62\",\n          \"colors\": [\"#6b9ce7\"]\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 63\",\n          \"colors\": [\"#a5c6f7\"]\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 64\",\n          \"colors\": [\"#0000bd\"]\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Dimmer Curves\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to Unit Setting\"\n        }\n      ]\n    },\n    \"Program Selection Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimming mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Macro mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Change mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Change Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Fade mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Fade Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound active mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Sound Active Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Change Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 16\"\n        }\n      ]\n    },\n    \"Color Fade Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 16\"\n        }\n      ]\n    },\n    \"Sound Active Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 16\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Shutter / Strobe\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Shutter / Strobe\",\n        \"Master Dimmer\",\n        \"Dimmer Curves\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Shutter / Strobe\",\n        \"Master Dimmer\",\n        \"Program Selection Mode\",\n        \"Program Selection\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Shutter / Strobe\",\n        \"Master Dimmer\",\n        \"Program Selection Mode\",\n        \"Program Selection\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Curves\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/crazy-pocket-8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Crazy Pocket 8\",\n  \"shortName\": \"ADJCrazyPocket8\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-05-08\",\n    \"lastModifyDate\": \"2019-05-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/8887/crazy_pocket_8.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/crazy-pocket-8\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=6P0B1ANc_I4\",\n      \"https://www.youtube.com/watch?v=mNvEVIV2qvE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [297.5, 262, 149],\n    \"weight\": 3.5,\n    \"power\": 59,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"8× 3W LEDs (2× red, 2× green, 2× blue, 2× amber)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 4]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [   \"Amber Top\",    \"Blue Top\",    \"Green Top\",    \"Red Top\"],\n        [         null,           null,           null,         null],\n        [\"Amber Bottom\", \"Blue Bottom\", \"Green Bottom\", \"Red Bottom\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Top\": { \"name\": [\" Top$\"] },\n      \"Bottom\": { \"name\": [\" Bottom$\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Shows\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [8, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 1\"\n        },\n        {\n          \"dmxRange\": [70, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 2\"\n        },\n        {\n          \"dmxRange\": [132, 193],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 3\"\n        },\n        {\n          \"dmxRange\": [194, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 4\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 0\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Chases\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [23, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [38, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [53, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [68, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 5\"\n        },\n        {\n          \"dmxRange\": [83, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 6\"\n        },\n        {\n          \"dmxRange\": [98, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 7\"\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 8\"\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 9\"\n        },\n        {\n          \"dmxRange\": [143, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 10\"\n        },\n        {\n          \"dmxRange\": [158, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 11\"\n        },\n        {\n          \"dmxRange\": [173, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 12\"\n        },\n        {\n          \"dmxRange\": [188, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 13\"\n        },\n        {\n          \"dmxRange\": [203, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 14\"\n        },\n        {\n          \"dmxRange\": [218, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 15\"\n        },\n        {\n          \"dmxRange\": [233, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 16\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full on\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffaa00\"]\n        }\n      ]\n    },\n    \"Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Reset / Blackout\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at pan/tilt movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset tilt top\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset tilt bottom\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan\"\n        },\n        {\n          \"dmxRange\": [110, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Dimmer Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default setting\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Tilt $pixelKey\": {\n      \"fineChannelAliases\": [\"Tilt $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"205deg\"\n      }\n    },\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Shows\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt Top\",\n        \"Tilt Bottom\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Chases\",\n        \"Chase Speed\",\n        \"Pan/Tilt Speed\",\n        \"Reset / Blackout\"\n      ]\n    },\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt Top\",\n        \"Tilt Top fine\",\n        \"Tilt Bottom\",\n        \"Tilt Bottom fine\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Chases\",\n        \"Chase Speed\",\n        \"Pan/Tilt Speed\",\n        \"Reset / Blackout\",\n        \"Dimmer Mode\"\n      ]\n    },\n    {\n      \"name\": \"21-channel\",\n      \"shortName\": \"21ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt Top\",\n        \"Tilt Top fine\",\n        \"Tilt Bottom\",\n        \"Tilt Bottom fine\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Top\", \"Bottom\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        },\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Chases\",\n        \"Chase Speed\",\n        \"Pan/Tilt Speed\",\n        \"Reset / Blackout\",\n        \"Dimmer Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/dekker-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Dekker LED\",\n  \"shortName\": \"ADJDekker\",\n  \"categories\": [\"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-05-08\",\n    \"lastModifyDate\": \"2019-05-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/7156/dekker_led.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/dekker-led\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vq36Zvue0dU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [280, 260, 251],\n    \"weight\": 3.85,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"2x 5W RGBW LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 26],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"4-color\"\n        },\n        {\n          \"dmxRange\": [27, 51],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"9-color\"\n        },\n        {\n          \"dmxRange\": [52, 76],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"4-color\"\n        },\n        {\n          \"dmxRange\": [77, 101],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"9-color\"\n        },\n        {\n          \"dmxRange\": [102, 126],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [127, 151],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [152, 176],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [177, 201],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [202, 226],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"9-color\"\n        },\n        {\n          \"dmxRange\": [227, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"gradual dim\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cycle all programs\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Rotation\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Intensity\",\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/dotz-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Dotz Par\",\n  \"shortName\": \"Dotz Par\",\n  \"categories\": [\"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"TAKU\", \"Felix Edelmann\", \"JonahKr\"],\n    \"createDate\": \"2018-04-09\",\n    \"lastModifyDate\": \"2021-09-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/8795/ADJ%20Dotz%20Par%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/dotz-par\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=0KXL39CwBp8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [114, 222, 209],\n    \"weight\": 2,\n    \"power\": 36,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"36W COB Tri LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\",\n          \"colors\": [\"#fcded8\"]\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\",\n          \"colors\": [\"#ffbe55\"]\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\",\n          \"colors\": [\"#fcd7b3\"]\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gallo Gold\",\n          \"colors\": [\"#fea562\"]\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\",\n          \"colors\": [\"#faa873\"]\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#f50000\"]\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\",\n          \"colors\": [\"#c8003c\"]\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\",\n          \"colors\": [\"#ffa0b9\"]\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Broadway Pink\",\n          \"colors\": [\"#e05061\"]\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Follies Pink\",\n          \"colors\": [\"#ff64c8\"]\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\",\n          \"colors\": [\"#e6aafa\"]\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\",\n          \"colors\": [\"#c8b4e6\"]\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#b46ef0\"]\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Indigo\",\n          \"colors\": [\"#002656\"]\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hemsley Blue\",\n          \"colors\": [\"#008ed0\"]\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tipton Blue\",\n          \"colors\": [\"#3494d1\"]\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Steel Blue\",\n          \"colors\": [\"#1086c9\"]\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Sky Blue\",\n          \"colors\": [\"#0091d4\"]\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#46b4f0\"]\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brilliant Blue\",\n          \"colors\": [\"#0081b8\"]\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green Blue\",\n          \"colors\": [\"#005373\"]\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\",\n          \"colors\": [\"#00d2e6\"]\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Blue\",\n          \"colors\": [\"#1064a7\"]\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\",\n          \"colors\": [\"#5000aa\"]\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow Green\",\n          \"colors\": [\"#d1dbb6\"]\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\",\n          \"colors\": [\"#5adc5a\"]\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\",\n          \"colors\": [\"#4bc300\"]\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CTB\",\n          \"colors\": [\"#806bde\"]\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color fade/change\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Curves\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 41],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [42, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [85, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [128, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [171, 213],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [214, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit curve setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Master Dimmer\",\n        \"Dimmer Curves\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Master Dimmer\",\n        \"Color Macros\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Strobe\",\n        \"Dimmer Curves\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/encore-lp12z-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Encore LP12Z IP\",\n  \"shortName\": \"encore-lp12z-ip\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Nikita\"],\n    \"createDate\": \"2024-09-12\",\n    \"lastModifyDate\": \"2024-09-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/13583/ADJ%20Encore%20LP12Z%20IP%20-%20User%20Manual%2002-22-2024.pdf\",\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/13583/ADJ%20Encore%20LP12Z%20IP%20-%20DMX%20Traits.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/encore-lp12z-ip\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=f_LbX1cYPYw\",\n      \"https://www.youtube.com/shorts/7YWwZOtYoiw\",\n      \"https://www.youtube.com/shorts/4KwpsqBNHNc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [371, 316, 346],\n    \"weight\": 7.5,\n    \"power\": 227,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 4400\n    },\n    \"lens\": {\n      \"degreesMinMax\": [5, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Lime\": {\n      \"fineChannelAliases\": [\"Lime fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#60ffee\"],\n          \"comment\": \"Red: 80, Green: 255, Blue: 234, Lime: 80\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#60ffa8\"],\n          \"comment\": \"Red: 80, Green: 255, Blue: 164, Lime: 80\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5cff73\"],\n          \"comment\": \"Red: 77, Green: 255, Blue: 112, Lime: 77\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#85ff57\"],\n          \"comment\": \"Red: 117, Green: 255, Blue: 83, Lime: 83\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#afff50\"],\n          \"comment\": \"Red: 160, Green: 255, Blue: 77, Lime: 77\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#efff57\"],\n          \"comment\": \"Red: 223, Green: 255, Blue: 83, Lime: 83\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff50\"],\n          \"comment\": \"Red: 255, Green: 243, Blue: 77, Lime: 77\"\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd64d\"],\n          \"comment\": \"Red: 255, Green: 200, Blue: 74, Lime: 74\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb550\"],\n          \"comment\": \"Red: 255, Green: 166, Blue: 77, Lime: 77\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8b4d\"],\n          \"comment\": \"Red: 255, Green: 125, Blue: 74, Lime: 74\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6f50\"],\n          \"comment\": \"Red: 255, Green: 97, Blue: 77, Lime: 71\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff5850\"],\n          \"comment\": \"Red: 255, Green: 74, Blue: 77, Lime: 71\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff638a\"],\n          \"comment\": \"Red: 255, Green: 83, Blue: 134, Lime: 83\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6fba\"],\n          \"comment\": \"Red: 255, Green: 93, Blue: 182, Lime: 93\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff73f0\"],\n          \"comment\": \"Red: 255, Green: 96, Blue: 236, Lime: 96\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6fff\"],\n          \"comment\": \"Red: 238, Green: 93, Blue: 255, Lime: 93\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b468ff\"],\n          \"comment\": \"Red: 163, Green: 87, Blue: 255, Lime: 87\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a86cff\"],\n          \"comment\": \"Red: 150, Green: 90, Blue: 255, Lime: 90\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#735cff\"],\n          \"comment\": \"Red: 100, Green: 77, Blue: 255, Lime: 77\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5c73ff\"],\n          \"comment\": \"Red: 77, Green: 100, Blue: 255, Lime: 77\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50a1ff\"],\n          \"comment\": \"Red: 67, Green: 148, Blue: 255, Lime: 67\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5cd2ff\"],\n          \"comment\": \"Red: 77, Green: 195, Blue: 255, Lime: 77\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5cf9ff\"],\n          \"comment\": \"Red: 77, Green: 234, Blue: 255, Lime: 77\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#baff97\"],\n          \"comment\": \"Red: 158, Green: 255, Blue: 144, Lime: 144\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffa0\"],\n          \"comment\": \"Red: 255, Green: 251, Blue: 153, Lime: 153\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffcc9a\"],\n          \"comment\": \"Red: 255, Green: 175, Blue: 147, Lime: 147\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa5c0\"],\n          \"comment\": \"Red: 255, Green: 138, Blue: 186, Lime: 138\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb0ff\"],\n          \"comment\": \"Red: 255, Green: 147, Blue: 251, Lime: 147\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b2a2ff\"],\n          \"comment\": \"Red: 151, Green: 135, Blue: 255, Lime: 138\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7714ff\"],\n          \"comment\": \"Red: 99, Green: 0, Blue: 255, Lime: 100\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a5c4ff\"],\n          \"comment\": \"Red: 138, Green: 169, Blue: 255, Lime: 138\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red: 255, Green: 255, Blue: 255, Lime: 255\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffce8f\"],\n          \"comment\": \"Red: 255, Green: 206, Blue: 143, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#feb199\"],\n          \"comment\": \"Red: 254, Green: 177, Blue: 153, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fec08a\"],\n          \"comment\": \"Red: 254, Green: 192, Blue: 138, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fea562\"],\n          \"comment\": \"Red: 254, Green: 165, Blue: 98, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fe7900\"],\n          \"comment\": \"Red: 254, Green: 121, Blue: 0, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b01100\"],\n          \"comment\": \"Red: 176, Green: 17, Blue: 0, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#60000b\"],\n          \"comment\": \"Red: 96, Green: 0, Blue: 11, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ea8bab\"],\n          \"comment\": \"Red: 234, Green: 139, Blue: 171, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e00561\"],\n          \"comment\": \"Red: 224, Green: 5, Blue: 97, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#af4dad\"],\n          \"comment\": \"Red: 175, Green: 77, Blue: 173, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7782c7\"],\n          \"comment\": \"Red: 119, Green: 130, Blue: 199, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#93a4d4\"],\n          \"comment\": \"Red: 147, Green: 164, Blue: 212, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5802a3\"],\n          \"comment\": \"Red: 88, Green: 2, Blue: 163, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002656\"],\n          \"comment\": \"Red: 0, Green: 38, Blue: 86, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#008ed0\"],\n          \"comment\": \"Red: 0, Green: 142, Blue: 208, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#3494d1\"],\n          \"comment\": \"Red: 52, Green: 148, Blue: 209, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0186cc\"],\n          \"comment\": \"Red: 1, Green: 134, Blue: 204, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0091d4\"],\n          \"comment\": \"Red: 0, Green: 145, Blue: 212, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0079c0\"],\n          \"comment\": \"Red: 0, Green: 121, Blue: 192, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0081b8\"],\n          \"comment\": \"Red: 0, Green: 129, Blue: 184, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#005373\"],\n          \"comment\": \"Red: 0, Green: 83, Blue: 115, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0061a6\"],\n          \"comment\": \"Red: 0, Green: 97, Blue: 166, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0164a7\"],\n          \"comment\": \"Red: 1, Green: 100, Blue: 167, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002856\"],\n          \"comment\": \"Red: 0, Green: 40, Blue: 86, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d1dbb6\"],\n          \"comment\": \"Red: 209, Green: 219, Blue: 182, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2aa555\"],\n          \"comment\": \"Red: 42, Green: 165, Blue: 85, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002e23\"],\n          \"comment\": \"Red: 0, Green: 46, Blue: 35, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#086bde\"],\n          \"comment\": \"Red: 8, Green: 107, Blue: 222, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red: 255, Green: 0, Blue: 0, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Red: 0, Green: 255, Blue: 0, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Red: 0, Green: 0, Blue: 255, Lime: 0\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#33330c\"],\n          \"comment\": \"Red: 0, Green: 0, Blue: 0, Lime: 255\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"in sequences\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Zoom Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Zoom\",\n          \"angle\": \"5deg\",\n          \"comment\": \"Normal\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Zoom\",\n          \"angle\": \"6deg\",\n          \"comment\": \"Very Narrow Spot\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Zoom\",\n          \"angle\": \"10deg\",\n          \"comment\": \"Narrow\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Zoom\",\n          \"angle\": \"30deg\",\n          \"comment\": \"Medium Flood\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Zoom\",\n          \"angle\": \"40deg\",\n          \"comment\": \"Wide Flood\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Zoom\",\n          \"angle\": \"50deg\",\n          \"comment\": \"Very Wide Flood\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2700K\",\n        \"colorTemperatureEnd\": \"7000K\",\n        \"comment\": \"linear\"\n      }\n    },\n    \"Color Temperature Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 54],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [55, 109],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [110, 164],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [165, 219],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        }\n      ]\n    },\n    \"Dim mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage 2\"\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"Time\",\n          \"timeStart\": \"0.1s\",\n          \"timeEnd\": \"10s\",\n          \"comment\": \"Dimmer speed\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inv Squa\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S Curve\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        },\n        {\n          \"dmxRange\": [16, 30],\n          \"type\": \"Maintenance\",\n          \"parameter\": 900,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [31, 45],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1000,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [46, 60],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1100,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [61, 75],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1200,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [76, 90],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1300,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [91, 105],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1400,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [106, 120],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1500,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [121, 135],\n          \"type\": \"Maintenance\",\n          \"parameter\": 2500,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [136, 150],\n          \"type\": \"Maintenance\",\n          \"parameter\": 4000,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [151, 165],\n          \"type\": \"Maintenance\",\n          \"parameter\": 5000,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [166, 180],\n          \"type\": \"Maintenance\",\n          \"parameter\": 10000,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [181, 195],\n          \"type\": \"Maintenance\",\n          \"parameter\": 15000,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [196, 210],\n          \"type\": \"Maintenance\",\n          \"parameter\": 20000,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [211, 225],\n          \"type\": \"Maintenance\",\n          \"parameter\": 25000,\n          \"comment\": \"Hz\"\n        },\n        {\n          \"dmxRange\": [226, 229],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Enable Zoom Mode 1\"\n        },\n        {\n          \"dmxRange\": [230, 233],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Enable Zoom Mode 2\"\n        },\n        {\n          \"dmxRange\": [234, 238],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom Reset\"\n        },\n        {\n          \"dmxRange\": [239, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Auto Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 6\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 7\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Auto Program Fade\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Lime\",\n        \"Zoom\",\n        \"Zoom Presets\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Lime\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Zoom Presets\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Lime\",\n        \"Lime fine\",\n        \"Zoom\",\n        \"Zoom Presets\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Lime\",\n        \"Color Macros\",\n        \"Color Temperature\",\n        \"Color Temperature Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Zoom Presets\"\n      ]\n    },\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Lime\",\n        \"Color Macros\",\n        \"Color Temperature\",\n        \"Color Temperature Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Zoom Presets\",\n        \"Dim mode\",\n        \"Dimmer Curve\",\n        \"Special Functions\"\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Lime\",\n        \"Color Macros\",\n        \"Color Temperature\",\n        \"Color Temperature Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Zoom Presets\",\n        \"Auto Program\",\n        \"Auto Program Speed\",\n        \"Auto Program Fade\",\n        \"Dim mode\",\n        \"Dimmer Curve\",\n        \"Special Functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/encore-profile-1000-ww.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Encore Profile 1000 WW\",\n  \"shortName\": \"ADJEncProfile1000WW\",\n  \"categories\": [\"Blinder\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Gerard Fontanillas\"],\n    \"createDate\": \"2019-02-27\",\n    \"lastModifyDate\": \"2019-02-27\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/8872/ADJ%20Encore%20Profile%201000%20WW%20-%20User%20Manual%2006-06-2023.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/encore-profile-1000-ww\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=zz6L0bJZoF8\",\n      \"https://www.youtube.com/watch?v=MdO71QLiFZ4\",\n      \"https://www.youtube.com/watch?v=SwFZg45s_hE\",\n      \"https://www.youtube.com/watch?v=2twVkEXGRBg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 385, 560],\n    \"weight\": 8.5,\n    \"power\": 144,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"120W warm white COB LED\",\n      \"colorTemperature\": 3200\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Warm White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Warm White\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Warm White\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Warm White\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/flat-par-qa12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flat Par QA12\",\n  \"shortName\": \"QA12\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"TAKU\", \"Flo Edelmann\", \"Ken Harris\"],\n    \"createDate\": \"2022-03-20\",\n    \"lastModifyDate\": \"2022-03-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/7028/flat_par_qa12.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/flat-par-qa12\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [280, 115, 328],\n    \"weight\": 3.2,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 5W RGBA LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6000\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#92ff00\"],\n          \"comment\": \"Lime\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbfff\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf00\"],\n          \"comment\": \"Warm Yellow\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6080\"],\n          \"comment\": \"Light Red\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#92ff92\"],\n          \"comment\": \"Light Green\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf80\"],\n          \"comment\": \"Light Amber\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Mode Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\",\n            \"Color Macros / Programs\": \"Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color macro mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\",\n            \"Color Macros / Programs\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color change mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Program Speed\",\n            \"Color Macros / Programs\": \"Color Change Programs\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color fade mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Program Speed\",\n            \"Color Macros / Programs\": \"Color Fade Programs\"\n          }\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound active mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Sound Sensitivity\",\n            \"Color Macros / Programs\": \"Sound Active Programs\"\n          }\n        }\n      ]\n    },\n    \"Color Change Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"16\"\n        }\n      ]\n    },\n    \"Color Fade Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"16\"\n        }\n      ]\n    },\n    \"Sound Active Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 16\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe / Speed / Sensitivity\",\n        \"Mode Select\",\n        \"Color Macros / Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/flat-par-qa12xs.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flat Par QA12XS\",\n  \"shortName\": \"QA12XS\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"TAKU\", \"Flo Edelmann\", \"Ken Harris\"],\n    \"createDate\": \"2018-08-05\",\n    \"lastModifyDate\": \"2022-03-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/8308/flat_par_qa12xs.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=JklRIKHLV3Y\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/flat-par-qa12xs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [280, 115, 328],\n    \"weight\": 3.2,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 5W RGBA LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6000\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#92ff00\"],\n          \"comment\": \"Lime\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbfff\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf00\"],\n          \"comment\": \"Warm Yellow\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6080\"],\n          \"comment\": \"Light Red\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#92ff92\"],\n          \"comment\": \"Light Green\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf80\"],\n          \"comment\": \"Light Amber\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Mode Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\",\n            \"Color Macros / Programs\": \"Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color macro mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\",\n            \"Color Macros / Programs\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color change mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Program Speed\",\n            \"Color Macros / Programs\": \"Color Change Programs\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color fade mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Program Speed\",\n            \"Color Macros / Programs\": \"Color Fade Programs\"\n          }\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound active mode\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Sound Sensitivity\",\n            \"Color Macros / Programs\": \"Sound Active Programs\"\n          }\n        }\n      ]\n    },\n    \"Color Change Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"16\"\n        }\n      ]\n    },\n    \"Color Fade Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"16\"\n        }\n      ]\n    },\n    \"Sound Active Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program 16\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe / Speed / Sensitivity\",\n        \"Mode Select\",\n        \"Color Macros / Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/fog-fury-jett-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Fog Fury Jett Pro\",\n  \"shortName\": \"FuryJettPro\",\n  \"categories\": [\"Smoke\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-08-06\",\n    \"lastModifyDate\": \"2018-11-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/10687/Fog%20Fury%20Jett%20Pro%20-%20User%20Manual%20(08-10-2022).pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/fog-fury-jett-pro\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=dN6IbP1x5Fo\",\n      \"https://www.youtube.com/watch?v=0mFX-qgHLbo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [419, 206, 315],\n    \"weight\": 9.5,\n    \"power\": 1550,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3W LEDs (6x Red, 7x Green, 6x Blue, 3x Amber, 6x UV)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Fog & Color Change\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"Fog\",\n          \"comment\": \"with color change\",\n          \"fogType\": \"Fog\",\n          \"fogOutput\": \"1133m^3/min\"\n        }\n      ]\n    },\n    \"Fog\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutput\": \"1133m^3/min\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"],\n          \"comment\": \"Blue + UV\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8800ff\"],\n          \"comment\": \"UV\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"],\n          \"comment\": \"Red + Blue + UV\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#92ff00\"],\n          \"comment\": \"OuterGreen + Amber\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"],\n          \"comment\": \"Red + UV\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbfff\"],\n          \"comment\": \"Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"InnerGreen + Blue\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Red + InnerGreen\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red + InnerGreen + Blue\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84cf78\"],\n          \"comment\": \"Colormix 1\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#89ff00\", \"#30005a\"],\n          \"comment\": \"Colormix 2 + UV\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6bfd00\", \"#6500be\"],\n          \"comment\": \"Colormix 3 + UV\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b98ce9\", \"#250046\"],\n          \"comment\": \"Colormix 4 + UV\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc916\", \"#6b00c8\"],\n          \"comment\": \"Colormix 5 + UV\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#35ff00\", \"#500096\"],\n          \"comment\": \"Colormix 6 + UV\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00c8c8\", \"#6b00c8\"],\n          \"comment\": \"Colormix 7 + UV\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2d7db4\", \"#20003c\"],\n          \"comment\": \"Colormix 8 + UV\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c8b1eb\"],\n          \"comment\": \"Colormix 9\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c9ff1a\", \"#1d0037\"],\n          \"comment\": \"Colormix 10 + UV\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#adff14\", \"#5b00aa\"],\n          \"comment\": \"Colormix 11 + UV\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#86ff00\", \"#350064\"],\n          \"comment\": \"Colormix 12 + UV\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8a00\"],\n          \"comment\": \"Colormix 13\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#645096\", \"#8800ff\"],\n          \"comment\": \"Colormix 14 + UV\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b4ff94\"],\n          \"comment\": \"Colormix 15\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#becf50\", \"#7600de\"],\n          \"comment\": \"Colormix 16 + UV\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"],\n          \"comment\": \"All on\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color 1\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color 2\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green (Outer LEDs)\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Green (Inner LEDs)\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Fog & Color Change\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Color Macros\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Red\",\n        \"Green (Outer LEDs)\",\n        \"Blue\",\n        \"Amber\",\n        \"Green (Inner LEDs)\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Red\",\n        \"Green (Outer LEDs)\",\n        \"Blue\",\n        \"Amber\",\n        \"Green (Inner LEDs)\",\n        \"UV\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/galaxian-3d.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Galaxian 3D\",\n  \"categories\": [\"Laser\"],\n  \"meta\": {\n    \"authors\": [\"eklynx\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-09-11\",\n    \"lastModifyDate\": \"2018-08-09\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2017-09-11\",\n      \"comment\": \"created by Q Light Controller (version 3.0.7)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/7184/galaxian_3d.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=-kcu0uBGF2Y\",\n      \"https://www.youtube.com/watch?v=sdMrkl5b1YE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [242, 71, 247],\n    \"weight\": 2.6,\n    \"power\": 22.5,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"30mW Green Diode Laser, 80mW Red Diode Laser\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [82, 82]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Red\", \"Green\"]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Laser\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"$pixelKey Laser Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red Laser\",\n        \"Green Laser\",\n        \"Red Laser Rotation\",\n        \"Green Laser Rotation\",\n        \"Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/illusion-dotz-4-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Illusion Dotz 4.4\",\n  \"categories\": [\"Matrix\", \"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dávid Czirók\", \"István Király\"],\n    \"createDate\": \"2019-10-30\",\n    \"lastModifyDate\": \"2019-10-30\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-10-30\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.1)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/8697/Illusion%20Dotz%204.4%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/illusion-dotz-4-4\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=NbQMI2cSr00\",\n      \"https://www.youtube.com/watch?v=9Q4ybDqgpP4\",\n      \"https://www.youtube.com/watch?v=m9pnTYFYrGs\",\n      \"https://www.youtube.com/watch?v=vyVgKv-uXws\"\n    ]\n  },\n  \"helpWanted\": \"Is the order of the individual pixels in Extended 59-channel mode correct?\",\n  \"physical\": {\n    \"dimensions\": [492, 467, 393],\n    \"weight\": 16.5,\n    \"power\": 468,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"16× 30W RGB COB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 4, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Curves\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit settings\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"helpWanted\": \"Does DMX value 0 really activate an auto program? Or does this capability start at 1 in fact?\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\"\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\"\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 21\"\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 22\"\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 23\"\n        },\n        {\n          \"dmxRange\": [231, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 24\"\n        },\n        {\n          \"dmxRange\": [241, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 25\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gradient effect\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pan/Tilt Movement Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"blackout by movement\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Maintenance / Internal Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motor reset\"\n        },\n        {\n          \"dmxRange\": [85, 96],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Is the lamp off when this capability is selected?\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Other motor reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 2\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 3\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 4\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 5\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 6\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 7\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active program\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard 14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer Curves\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Pan/Tilt Movement Speed\",\n        \"Maintenance / Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"Basic 12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer Curves\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Pan/Tilt Movement Speed\",\n        \"Maintenance / Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"Extended 59-channel\",\n      \"shortName\": \"59ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer Curves\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Pan/Tilt Movement Speed\",\n        \"Maintenance / Internal Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/inno-pocket-beam-q4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Inno Pocket Beam Q4\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"jc\"],\n    \"createDate\": \"2019-02-15\",\n    \"lastModifyDate\": \"2019-02-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://adjmedia.s3-website-eu-west-1.amazonaws.com/manuals/Inno%20Pocket%20Beam%20Q4.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.eu/inno-pocket-beam-q4\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ldCt6rDwOQM\",\n      \"https://www.youtube.com/watch?v=zG4iWzimoqU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [147, 265, 159],\n    \"weight\": 3,\n    \"power\": 45.6,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"15W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 4]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"defaultValue\": \"50%\",\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": \"50%\",\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 8,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 248],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [249, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Maintenance\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by pan/tilt movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by color change\"\n        },\n        {\n          \"dmxRange\": [100, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Dimmer Curves\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default unit curve\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Maintenance\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Maintenance\",\n        \"Dimmer Curves\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Maintenance\",\n        \"Dimmer Curves\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/inno-pocket-fusion.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Inno Pocket Fusion\",\n  \"shortName\": \"ADJInnoPocketFusion\",\n  \"categories\": [\"Barrel Scanner\", \"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"EXELBONSAI\"],\n    \"createDate\": \"2018-07-26\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/8780/inno_pocket_fusion.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/inno-pocket-fusion\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=hLYHfn-D5aY\",\n      \"https://www.youtube.com/watch?v=Zdd0t-rlqck\",\n      \"https://www.youtube.com/watch?v=uy0yZrFI4zg\"\n    ],\n    \"other\": [\"https://www.qlcplus.org/forum/viewtopic.php?f=6&t=12415\"]\n  },\n  \"physical\": {\n    \"dimensions\": [340, 177, 132],\n    \"weight\": 3.4,\n    \"power\": 32,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12W White LED + 4.9mW Green Laser Diode\",\n      \"lumens\": 50\n    },\n    \"lens\": {\n      \"degreesMinMax\": [2, 5]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#77ccff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Tilt\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 120],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [135, 245],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"LED Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Laser Movement\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 120],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [121, 135],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [136, 245],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Laser Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Show\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 1\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 2\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 3\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [86, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 4\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 5\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [138, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 6\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [164, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 7\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 8\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Show\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Show Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default dimmer setting\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while pan movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while color wheel movement\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [100, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"LED Strobe\",\n        \"Master Dimmer\",\n        \"Laser Movement\",\n        \"Laser Strobe\",\n        \"Show\",\n        \"Show Speed / Sound Sensitivity\",\n        \"Dimmer Mode\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"LED Strobe\",\n        \"Master Dimmer\",\n        \"Laser Movement\",\n        \"Laser Strobe\",\n        \"Dimmer Mode\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"LED Strobe\",\n        \"Master Dimmer\",\n        \"Laser Movement\",\n        \"Laser Strobe\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Show\",\n        \"Show Speed / Sound Sensitivity\",\n        \"LED Strobe\",\n        \"Master Dimmer\",\n        \"Laser Strobe\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Show\",\n        \"Show Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/inno-pocket-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Inno Pocket Spot\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2026-04-21\",\n    \"lastModifyDate\": \"2026-04-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/6902/inno_pocket_spot.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/inno-pocket-spot\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=eLkPO3C_jVQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [159, 147, 265],\n    \"weight\": 3,\n    \"power\": 27,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 12W White LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#007fff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff6aff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 7\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [15, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [36, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [43, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [50, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [57, 66],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [67, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [77, 86],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [87, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [97, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [107, 116],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [117, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"comment\": \"same rotation direction as earlier range\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"comment\": \"same rotation direction as earlier range\"\n        }\n      ]\n    },\n    \"Shutter/Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"19Hz\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Blackout/Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with pan/tilt movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout with pan/tilt movement\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with color change\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout with color change\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with gobo change\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout with gobo change\"\n        },\n        {\n          \"dmxRange\": [130, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Dimmer Curves\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit curve setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter/Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Blackout/Reset\",\n        \"Dimmer Curves\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter/Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Blackout/Reset\",\n        \"Dimmer Curves\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/inno-spot-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Inno Spot Pro\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\", \"Chemin Rouge Evènements\"],\n    \"createDate\": \"2022-03-19\",\n    \"lastModifyDate\": \"2026-02-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/6922/inno_spot_pro.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/inno-spot-pro\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=qZIVSOfQyBE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [288, 425, 167],\n    \"weight\": 8.5,\n    \"power\": 140,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 80W White LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 17]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#b803b8\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#007fff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff6aff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Spot\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"240deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [15, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [36, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [43, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [50, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [57, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [64, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2,\n          \"helpWanted\": \"Is the wheel exactly halfway between White and Red for every DMX value in this capability? Or does the DMX value influence the proportion between the two?\"\n        },\n        {\n          \"dmxRange\": [71, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [78, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [85, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [92, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [99, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [106, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [113, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 0,\n          \"slotNumberEnd\": 1\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [19, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [28, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [46, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [55, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 73],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [74, 82],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [83, 91],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [92, 100],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [101, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [110, 118],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [119, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Assuming this is CW, analogous to the color wheel (but speed is backward?)\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\",\n          \"helpWanted\": \"Assuming this is CCW, analogous to the color wheel (but speed is backward?)\"\n        }\n      ]\n    },\n    \"Gobo Stencil Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"12Hz\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Blackout/Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with pan/tilt movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout pan tilt movement\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with color change\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout with color change\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with gobo change\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout with gobo change\"\n        },\n        {\n          \"dmxRange\": [130, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Blackout/Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/mega-bar-50rgb-rc.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mega Bar 50RGB RC\",\n  \"categories\": [\"Color Changer\", \"Strobe\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Peter G.\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-12-13\",\n    \"lastModifyDate\": \"2019-12-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/7103/mega_bar_50rgb_rc.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/mega-bar-50rgb-rc\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=8Px1FM_7BU8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [560, 63, 102],\n    \"weight\": 1.5,\n    \"power\": 18,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"125× 10mm LEDs (24× red, 54× green, 47× blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"Which exact colors are these?\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color Mixing\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3 Color Change\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 Color Change\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Intensity\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe / Program Speed / Sound Sensitivity\",\n        \"Program\",\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/mega-bar-50rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mega Bar 50RGB\",\n  \"categories\": [\"Color Changer\", \"Strobe\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Peter G.\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-12-13\",\n    \"lastModifyDate\": \"2019-12-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/7191/mega_bar_50rgb.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/mega-bar-50-rgb\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=F4gV5-FdGl0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [560, 63, 102],\n    \"weight\": 1.5,\n    \"power\": 18,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"125× 10mm LEDs (24× red, 54× green, 47× blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"Which exact colors are these?\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color Mixing\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3 Color Change\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 Color Change\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Intensity\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe / Program Speed / Sound Sensitivity\",\n        \"Program\",\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/mega-bar-rgba.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mega Bar RGBA\",\n  \"shortName\": \"ADJMBRGBA\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2018-12-10\",\n    \"lastModifyDate\": \"2018-12-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/6989/ADJ%20Mega%20Bar%20RGBA%20-%20User%20Manual%202023-04-11.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/mega-bar-rgba\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=WXp4BXd6yC8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1060, 145, 73],\n    \"weight\": 2.7,\n    \"power\": 32,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"320x 10mm LEDs (64 red, 96 green, 96 blue, 64 amber)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [125, 50, 10],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [8, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": [\"1\", \"2\", \"3\", \"4\"],\n      \"2/2\": [\"5\", \"6\", \"7\", \"8\"],\n      \"1/4\": [\"1\", \"2\"],\n      \"2/4\": [\"3\", \"4\"],\n      \"3/4\": [\"5\", \"6\"],\n      \"4/4\": [\"7\", \"8\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"stop\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm Yellow\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\",\n          \"colors\": [\"#ffce8f\"]\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\",\n          \"colors\": [\"#feb199\"]\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\",\n          \"colors\": [\"#fec08a\"]\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\",\n          \"colors\": [\"#fea562\"]\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\",\n          \"colors\": [\"#fe7900\"]\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\",\n          \"colors\": [\"#b01100\"]\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\",\n          \"colors\": [\"#60000b\"]\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\",\n          \"colors\": [\"#ea8bab\"]\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\",\n          \"colors\": [\"#fe0561\"]\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\",\n          \"colors\": [\"#af4dad\"]\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\",\n          \"colors\": [\"#7782c7\"]\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\",\n          \"colors\": [\"#93a4d4\"]\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\",\n          \"colors\": [\"#5802a3\"]\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\",\n          \"colors\": [\"#002656\"]\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\",\n          \"colors\": [\"#008ed0\"]\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32\",\n          \"colors\": [\"#3494d1\"]\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 33\",\n          \"colors\": [\"#0186c9\"]\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 34\",\n          \"colors\": [\"#0091d4\"]\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 35\",\n          \"colors\": [\"#0079c0\"]\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 36\",\n          \"colors\": [\"#0081b8\"]\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 37\",\n          \"colors\": [\"#005373\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 38\",\n          \"colors\": [\"#0061a6\"]\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 39\",\n          \"colors\": [\"#0164a7\"]\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 40\",\n          \"colors\": [\"#002856\"]\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 41\",\n          \"colors\": [\"#d1dbb6\"]\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 42\",\n          \"colors\": [\"#2aa555\"]\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 43\",\n          \"colors\": [\"#002e23\"]\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 44\",\n          \"colors\": [\"#086bde\"]\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 45\",\n          \"colors\": [\"#6b9ce7\"]\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 46\",\n          \"colors\": [\"#a5c6f7\"]\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 47\",\n          \"colors\": [\"#0000bd\"]\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 48\",\n          \"colors\": [\"#a52301\"]\n        }\n      ]\n    },\n    \"Flow Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm Yellow\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\",\n          \"colors\": [\"#ffce8f\"]\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\",\n          \"colors\": [\"#feb199\"]\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\",\n          \"colors\": [\"#fec08a\"]\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\",\n          \"colors\": [\"#fea562\"]\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\",\n          \"colors\": [\"#fe7900\"]\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\",\n          \"colors\": [\"#b01100\"]\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\",\n          \"colors\": [\"#60000b\"]\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\",\n          \"colors\": [\"#ea8bab\"]\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\",\n          \"colors\": [\"#fe0561\"]\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\",\n          \"colors\": [\"#af4dad\"]\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\",\n          \"colors\": [\"#7782c7\"]\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\",\n          \"colors\": [\"#93a4d4\"]\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\",\n          \"colors\": [\"#5802a3\"]\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\",\n          \"colors\": [\"#002656\"]\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\",\n          \"colors\": [\"#008ed0\"]\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32\",\n          \"colors\": [\"#3494d1\"]\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 33\",\n          \"colors\": [\"#0186c9\"]\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 34\",\n          \"colors\": [\"#0091d4\"]\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 35\",\n          \"colors\": [\"#0079c0\"]\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 36\",\n          \"colors\": [\"#0081b8\"]\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 37\",\n          \"colors\": [\"#005373\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 38\",\n          \"colors\": [\"#0061a6\"]\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 39\",\n          \"colors\": [\"#0164a7\"]\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 40\",\n          \"colors\": [\"#002856\"]\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 41\",\n          \"colors\": [\"#d1dbb6\"]\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 42\",\n          \"colors\": [\"#2aa555\"]\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 43\",\n          \"colors\": [\"#002e23\"]\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 44\",\n          \"colors\": [\"#086bde\"]\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 45\",\n          \"colors\": [\"#6b9ce7\"]\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 46\",\n          \"colors\": [\"#a5c6f7\"]\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 47\",\n          \"colors\": [\"#0000bd\"]\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 48\",\n          \"colors\": [\"#a52301\"]\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [76, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [106, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [116, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [126, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [146, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [156, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [186, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [196, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [206, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 21\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Flow Color Macro\"\n          }\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 22\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Flow Color Macro\"\n          }\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto run\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\",\n            \"Amber Master / Flow Color Macro\": \"Amber Master\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGBA\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\"\n      ]\n    },\n    {\n      \"name\": \"RGBA + Strobe/Dimmer\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Strobe\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Color macro\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Program\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master / Flow Color Macro\",\n        \"Color Macros\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Strobe\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Halves\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        },\n        \"Strobe\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Fourths\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        },\n        \"Strobe\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Eighths\",\n      \"shortName\": \"34ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        },\n        \"Strobe\",\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/mega-hex-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mega Hex Par\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Christopher Haywood\", \"Ken Harris\"],\n    \"createDate\": \"2019-02-27\",\n    \"lastModifyDate\": \"2024-01-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/11285/ADJ%20Mega%20Hex%20Par%20-%20USER%20MANUAL%2006-19-2023.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/mega-hex-par\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VOx_gAC7YgA\",\n      \"https://www.youtube.com/watch?v=OxpR6C03JCE\",\n      \"https://www.youtube.com/watch?v=1guvuqWfwn4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [261, 260, 110],\n    \"weight\": 1.87,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Program Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Dimming Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Macro Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Change Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Color Change Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Fade Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Color Fade Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound Active Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Sound Active Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Off\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+A\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+UV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+A\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+UV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+A\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+UV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+A\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+UV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A+UV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+A\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+UV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+A\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+UV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+A\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+UV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+A+UV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+A\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+UV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+A\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+UV\",\n          \"colors\": [\"#80ff80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+A+UV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+A\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+UV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+A+UV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+A+UV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+A\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+UV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+A\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+UV\",\n          \"colors\": [\"#ffff80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+A+UV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W+A\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W+UV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+A+UV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+A+UV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+A\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+UV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+A+UV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+A+UV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+A+UV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+A\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+UV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+A+UV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+A+UV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W+A+UV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+A+UV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+A+UV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Change Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Jump 16\"\n        }\n      ]\n    },\n    \"Color Fade Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade 16\"\n        }\n      ]\n    },\n    \"Sound Active Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 16\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Master Dimmer\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Master Dimmer\",\n        \"Shutter / Strobe\",\n        \"Program Mode\",\n        \"Color Macros / Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Master Dimmer\",\n        \"Shutter / Strobe\",\n        \"Program Mode\",\n        \"Color Macros / Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/mega-par-profile-plus.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mega Par Profile Plus\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Glenn Meder\", \"NikolaPi\"],\n    \"createDate\": \"2026-01-28\",\n    \"lastModifyDate\": \"2026-01-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/8761/ADJ%20Mega%20Par%20Profile%20Plus%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/mega-par-profile-plus\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=g0ON1EzrZzQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [225, 220, 85],\n    \"weight\": 1.1,\n    \"power\": 16,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Program Selection Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimming Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Macro Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Change Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Change Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Fade Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Fade Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound Active Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Sound Active Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50ffea\", \"#2b0050\"],\n          \"comment\": \"Color 1, 31% UV\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50ffa4\", \"#2b0050\"],\n          \"comment\": \"Color 2, 31% UV\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4dff70\", \"#29004d\"],\n          \"comment\": \"Color 3, 30% UV\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#75ff53\", \"#2c0053\"],\n          \"comment\": \"Color 4, 32% UV\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a0ff4d\", \"#29004d\"],\n          \"comment\": \"Color 5, 30% UV\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dfff53\", \"#2c0053\"],\n          \"comment\": \"Color 6, 33% UV\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fff34d\", \"#29004d\"],\n          \"comment\": \"Color 7, 30% UV\"\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc84a\", \"#27004a\"],\n          \"comment\": \"Color 8, 29% UV\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa64d\", \"#29004d\"],\n          \"comment\": \"Color 9, 30% UV\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7d4a\", \"#27004a\"],\n          \"comment\": \"Color 10, 29% UV\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff614d\", \"#27004a\"],\n          \"comment\": \"Color 11, 29% UV\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff474d\", \"#260047\"],\n          \"comment\": \"Color 12, 28% UV\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff5386\", \"#2c0053\"],\n          \"comment\": \"Color 13, 33% UV\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff5db6\", \"#32005d\"],\n          \"comment\": \"Color 14, 36% UV\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff60ec\", \"#330060\"],\n          \"comment\": \"Color 15, 38% UV\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ee5dff\", \"#32005d\"],\n          \"comment\": \"Color 16, 36% UV\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c457ff\", \"#2e0057\"],\n          \"comment\": \"Color 17, 34% UV\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#965aff\", \"#30005a\"],\n          \"comment\": \"Color 18, 35% UV\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#644dff\", \"#29004d\"],\n          \"comment\": \"Color 19, 30% UV\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4d64ff\", \"#29004d\"],\n          \"comment\": \"Color 20, 30% UV\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4394ff\", \"#240043\"],\n          \"comment\": \"Color 21, 26% UV\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4dc3ff\", \"#29004d\"],\n          \"comment\": \"Color 22, 30% UV\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4deaff\", \"#29004d\"],\n          \"comment\": \"Color 23, 30% UV\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#9eff90\", \"#4d0090\"],\n          \"comment\": \"Color 24, 56% UV\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffb99\", \"#520099\"],\n          \"comment\": \"Color 25, 60% UV\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaf93\", \"#4e0093\"],\n          \"comment\": \"Color 26, 58% UV\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8aba\", \"#4a008a\"],\n          \"comment\": \"Color 27, 54% UV\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff93fb\", \"#4e0093\"],\n          \"comment\": \"Color 28, 58% UV\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#978aff\", \"#4a008a\"],\n          \"comment\": \"Color 29, 54% UV\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#978aff\", \"#4a008a\"],\n          \"comment\": \"Color 30, 54% UV\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8aa9ff\", \"#4a008a\"],\n          \"comment\": \"Color 31, 54% UV\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"],\n          \"comment\": \"White + 100% UV\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffce8f\"],\n          \"comment\": \"Color 33\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#feb199\"],\n          \"comment\": \"Color 34\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fec08a\"],\n          \"comment\": \"Color 35\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fea562\"],\n          \"comment\": \"Color 36\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fe7900\"],\n          \"comment\": \"Color 37\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b01100\"],\n          \"comment\": \"Color 38\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#60000b\"],\n          \"comment\": \"Color 39\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ea8bab\"],\n          \"comment\": \"Color 40\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e00561\"],\n          \"comment\": \"Color 41\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#af4dad\"],\n          \"comment\": \"Color 42\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7782c7\"],\n          \"comment\": \"Color 43\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#93a4d4\"],\n          \"comment\": \"Color 44\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5802a3\"],\n          \"comment\": \"Color 45\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002656\"],\n          \"comment\": \"Color 46\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#008ed0\"],\n          \"comment\": \"Color 47\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#3494d1\"],\n          \"comment\": \"Color 48\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0186c9\"],\n          \"comment\": \"Color 49\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0091d4\"],\n          \"comment\": \"Color 50\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#005373\"],\n          \"comment\": \"Color 53\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0061a6\"],\n          \"comment\": \"Color 54\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0164a7\"],\n          \"comment\": \"Color 55\"\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002856\"],\n          \"comment\": \"Color 56\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d1dbb6\"],\n          \"comment\": \"Color 57\"\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2aa555\"],\n          \"comment\": \"Color 58\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002e23\"],\n          \"comment\": \"Color 59\"\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#086bde\"],\n          \"comment\": \"Color 60\"\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6b9ce7\"],\n          \"comment\": \"Color 61\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a5c6f7\"],\n          \"comment\": \"Color 62\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8800ff\"],\n          \"comment\": \"UV\"\n        }\n      ]\n    },\n    \"Color Change Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 16\"\n        }\n      ]\n    },\n    \"Color Fade Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 16\"\n        }\n      ]\n    },\n    \"Sound Active Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 16\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer Curves\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to Unit Setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Blue\",\n        \"Green\",\n        \"UV\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Program Selection Mode\",\n        \"Program Selection\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Program Selection Mode\",\n        \"Program Selection\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Curves\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/mega-tripar-profile-plus.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mega TRIPAR Profile Plus\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Glenn Meder\"],\n    \"createDate\": \"2019-07-11\",\n    \"lastModifyDate\": \"2019-07-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/8800/Mega%20TRIPAR%20Profile%20Plus.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/mega-tripar-profile-plus\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=9z1gcBc233Q\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [225, 220, 85],\n    \"weight\": 1.23,\n    \"power\": 21,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 1173\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter/Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Program Selection Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimming Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Macro Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Change Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Change Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Fade Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Color Fade Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound Active Mode\",\n          \"switchChannels\": {\n            \"Program Selection\": \"Sound Active Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Black\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50ffea\", \"#2b0050\"],\n          \"comment\": \"Color 1, 31% UV\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50ffa4\", \"#2b0050\"],\n          \"comment\": \"Color 2, 31% UV\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4dff70\", \"#29004d\"],\n          \"comment\": \"Color 3, 30% UV\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#75ff53\", \"#2c0053\"],\n          \"comment\": \"Color 4, 32% UV\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a0ff4d\", \"#29004d\"],\n          \"comment\": \"Color 5, 30% UV\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dfff53\", \"#2c0053\"],\n          \"comment\": \"Color 6, 33% UV\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fff34d\", \"#29004d\"],\n          \"comment\": \"Color 7, 30% UV\"\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc84a\", \"#27004a\"],\n          \"comment\": \"Color 8, 29% UV\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa64d\", \"#29004d\"],\n          \"comment\": \"Color 9, 30% UV\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7d4a\", \"#27004a\"],\n          \"comment\": \"Color 10, 29% UV\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff614d\", \"#27004a\"],\n          \"comment\": \"Color 11, 29% UV\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff474d\", \"#260047\"],\n          \"comment\": \"Color 12, 28% UV\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff5386\", \"#2c0053\"],\n          \"comment\": \"Color 13, 33% UV\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff5db6\", \"#32005d\"],\n          \"comment\": \"Color 14, 36% UV\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff60ec\", \"#330060\"],\n          \"comment\": \"Color 15, 38% UV\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ee5dff\", \"#32005d\"],\n          \"comment\": \"Color 16, 36% UV\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c457ff\", \"#2e0057\"],\n          \"comment\": \"Color 17, 34% UV\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#965aff\", \"#30005a\"],\n          \"comment\": \"Color 18, 35% UV\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#644dff\", \"#29004d\"],\n          \"comment\": \"Color 19, 30% UV\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4d64ff\", \"#29004d\"],\n          \"comment\": \"Color 20, 30% UV\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4394ff\", \"#240043\"],\n          \"comment\": \"Color 21, 26% UV\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4dc3ff\", \"#29004d\"],\n          \"comment\": \"Color 22, 30% UV\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4deaff\", \"#29004d\"],\n          \"comment\": \"Color 23, 30% UV\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#9eff90\", \"#4d0090\"],\n          \"comment\": \"Color 24, 56% UV\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffb99\", \"#520099\"],\n          \"comment\": \"Color 25, 60% UV\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaf93\", \"#4e0093\"],\n          \"comment\": \"Color 26, 58% UV\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8aba\", \"#4a008a\"],\n          \"comment\": \"Color 27, 54% UV\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff93fb\", \"#4e0093\"],\n          \"comment\": \"Color 28, 58% UV\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#978aff\", \"#4a008a\"],\n          \"comment\": \"Color 29, 54% UV\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#978aff\", \"#4a008a\"],\n          \"comment\": \"Color 30, 54% UV\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8aa9ff\", \"#4a008a\"],\n          \"comment\": \"Color 31, 54% UV\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"],\n          \"comment\": \"White + 100% UV\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffce8f\"],\n          \"comment\": \"Color 33\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#feb199\"],\n          \"comment\": \"Color 34\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fec08a\"],\n          \"comment\": \"Color 35\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fea562\"],\n          \"comment\": \"Color 36\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fe7900\"],\n          \"comment\": \"Color 37\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b01100\"],\n          \"comment\": \"Color 38\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#60000b\"],\n          \"comment\": \"Color 39\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ea8bab\"],\n          \"comment\": \"Color 40\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e00561\"],\n          \"comment\": \"Color 41\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#af4dad\"],\n          \"comment\": \"Color 42\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7782c7\"],\n          \"comment\": \"Color 43\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#93a4d4\"],\n          \"comment\": \"Color 44\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5802a3\"],\n          \"comment\": \"Color 45\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002656\"],\n          \"comment\": \"Color 46\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#008ed0\"],\n          \"comment\": \"Color 47\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#3494d1\"],\n          \"comment\": \"Color 48\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0186c9\"],\n          \"comment\": \"Color 49\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0091d4\"],\n          \"comment\": \"Color 50\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#005373\"],\n          \"comment\": \"Color 53\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0061a6\"],\n          \"comment\": \"Color 54\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0164a7\"],\n          \"comment\": \"Color 55\"\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002856\"],\n          \"comment\": \"Color 56\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d1dbb6\"],\n          \"comment\": \"Color 57\"\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2aa555\"],\n          \"comment\": \"Color 58\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002e23\"],\n          \"comment\": \"Color 59\"\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#086bde\"],\n          \"comment\": \"Color 60\"\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6b9ce7\"],\n          \"comment\": \"Color 61\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a5c6f7\"],\n          \"comment\": \"Color 62\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8800ff\"],\n          \"comment\": \"UV\"\n        }\n      ]\n    },\n    \"Color Change Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 16\"\n        }\n      ]\n    },\n    \"Color Fade Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Program 16\"\n        }\n      ]\n    },\n    \"Sound Active Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Program 16\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer Curves\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to Unit Setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4 channel\",\n      \"shortName\": \"Ch04\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"5 channel\",\n      \"shortName\": \"Ch05\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6 channel\",\n      \"shortName\": \"Ch06\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Shutter/Strobe\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"9 channel\",\n      \"shortName\": \"Ch09\",\n      \"channels\": [\n        \"Red\",\n        \"Blue\",\n        \"Green\",\n        \"UV\",\n        \"Shutter/Strobe\",\n        \"Master Dimmer\",\n        \"Program Selection Mode\",\n        \"Program Selection\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"10 channel\",\n      \"shortName\": \"Ch10\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Shutter/Strobe\",\n        \"Master Dimmer\",\n        \"Program Selection Mode\",\n        \"Program Selection\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Curves\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/mega-tripar-profile.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mega TRIPAR Profile\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Glenn Meder\", \"Ryan Goodwin\", \"Ken Harris\"],\n    \"createDate\": \"2019-07-13\",\n    \"lastModifyDate\": \"2025-03-25\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/7049/mega_tripar_profile.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/mega-tripar-profile\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=NFXLK0EjYCQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [225, 220, 85],\n    \"weight\": 1.2,\n    \"power\": 16,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 519\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Color macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gallo Gold\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Broadway Pink\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Follies Pink\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Indigo\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hemsley Blue\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tipton Blue\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Steel Blue\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Sky Blue\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brilliant Blue\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green Blue\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Blue\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow Green\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CTB\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CTB\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Half CTB\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Can Sound Sensitivity already be controlled in this capability?\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 1\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 2\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 3\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 4\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 5\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 6\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 7\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 8\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change 1\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change 2\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change 2\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change 4\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change 5\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change 6\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Mode 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Mode 2\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"Ch.01\",\n      \"channels\": [\n        \"Color macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"Ch.02\",\n      \"channels\": [\n        \"Color macros\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"Ch.03\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"Ch.04\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"Ch.05\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Color macros\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"Ch.06\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color macros\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"Ch.07\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color macros\",\n        \"Strobe / Program Speed / Sound Sensitivity\",\n        \"Programs\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/mod-hex100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MOD HEX100\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"K\", \"Ryan Goodwin\"],\n    \"createDate\": \"2023-04-24\",\n    \"lastModifyDate\": \"2023-04-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/11302/ADJ%20MOD%20HEX100%20User%20Manual%20.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/mod-hex100\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=-X430bUWt50\"\n    ]\n  },\n  \"physical\": {\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"dimensions\": [140, 172, 140],\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Program Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Dimming Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Macro Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Color Macros\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Change Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Color Change Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Fade Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Color Fade Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound Active Mode\",\n          \"switchChannels\": {\n            \"Color Macros / Programs\": \"Sound Active Programs\",\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+A\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+UV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+A\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+UV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+A\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+UV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+A\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+UV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A+UV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+A\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+UV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+A\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+UV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+A\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+UV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+A+UV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+A\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+UV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+A\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+UV\",\n          \"colors\": [\"#80ff80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+A+UV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+A\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+UV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+A+UV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+A+UV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+A\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+UV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+A\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+UV\",\n          \"colors\": [\"#ffff80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+A+UV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W+A\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W+UV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+A+UV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+A+UV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+A\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+UV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+A+UV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+A+UV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+A+UV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+A\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+UV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+A+UV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+A+UV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W+A+UV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+A+UV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+A+UV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Change Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"16\"\n        }\n      ]\n    },\n    \"Color Fade Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"16\"\n        }\n      ]\n    },\n    \"Sound Active Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program 16\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Program Mode\",\n        \"Color Macros / Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Program Mode\",\n        \"Color Macros / Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/pocket-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Pocket Pro\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2019-03-16\",\n    \"lastModifyDate\": \"2019-03-16\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/11246/ADJ%20Pocket%20Pro%20%20Pocket%20Pro%20Pearl%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/pocket-pro\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=KOGvGZemSUA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [147, 265, 159],\n    \"weight\": 3.6,\n    \"power\": 53,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"25W white LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Glass\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Stars\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Squares\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Astrisk\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Leaves\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Diamonds\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bubbles\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [15, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [36, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [43, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [50, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [57, 66],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [67, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [77, 86],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [87, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [97, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [107, 116],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [117, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 8,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 28\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 29\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 30\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 31\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Curves\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit dimmer setting\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable Pan & Tilt Blackout\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable Pan & Tilt Blackout\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Target Mode 1 (0-180°)\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Target Mode 2 (90-270°)\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Target Mode (180-360°)\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Target Mode 4 (270-54°0)\"\n        },\n        {\n          \"dmxRange\": [130, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset All\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Pan/Tilt Macros\",\n        \"Pan/Tilt Macro Speed\",\n        \"Dimmer Curves\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Pan/Tilt Macros\",\n        \"Pan/Tilt Macro Speed\",\n        \"Dimmer Curves\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/quad-phase-hp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Quad Phase HP\",\n  \"shortName\": \"QPHP\",\n  \"categories\": [\"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-04-09\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/6976/ADJ%20Quad%20Phase%20HP%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/quad-phase-hp\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=g3qTCXyDvK8\",\n      \"https://www.youtube.com/watch?v=pxrg2VxH0xY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [198, 279, 312],\n    \"weight\": 4,\n    \"power\": 64,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [65, 65]\n    }\n  },\n  \"availableChannels\": {\n    \"Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [17, 33],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [34, 50],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [51, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [68, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [85, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [102, 118],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"],\n          \"comment\": \"Red + White\"\n        },\n        {\n          \"dmxRange\": [119, 135],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [136, 152],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Green + White\"\n        },\n        {\n          \"dmxRange\": [153, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [170, 186],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [187, 203],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Red + Green + White\"\n        },\n        {\n          \"dmxRange\": [204, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Blue + White\"\n        },\n        {\n          \"dmxRange\": [221, 237],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + White\"\n        }\n      ]\n    },\n    \"Rotation\": {\n      \"defaultValue\": 128,\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 120],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [135, 245],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [246, 249],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"highlightValue\": 200,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Strobe\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Color\",\n        \"Rotation\",\n        \"Strobe\",\n        \"Shutter\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/revo-4-ir.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Revo 4 IR\",\n  \"shortName\": \"Revo4IR\",\n  \"categories\": [\"Flower\", \"Matrix\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-05-24\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"http://adjmedia.s3-website-eu-west-1.amazonaws.com/manuals/revo_4_ir.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=t_t7wpYAKN8\",\n      \"https://www.youtube.com/watch?v=bERUdIplo9I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [312, 334, 304],\n    \"weight\": 4.9,\n    \"power\": 34,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"matrix\": {\n    \"pixelCount\": [8, 8, 1]\n  },\n  \"availableChannels\": {\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"switchChannels\": {\n            \"Color / Chase Speed\": \"Color\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern\",\n          \"switchChannels\": {\n            \"Color / Chase Speed\": \"Color\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase\",\n          \"switchChannels\": {\n            \"Color / Chase Speed\": \"Chase Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color / Chase Speed\": \"Chase Speed\"\n          }\n        }\n      ]\n    },\n    \"Pattern / Chase\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 1\"\n        },\n        {\n          \"dmxRange\": [21, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 2\"\n        },\n        {\n          \"dmxRange\": [42, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 3\"\n        },\n        {\n          \"dmxRange\": [66, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 4\"\n        },\n        {\n          \"dmxRange\": [88, 108],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 5\"\n        },\n        {\n          \"dmxRange\": [109, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 6\"\n        },\n        {\n          \"dmxRange\": [130, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 7\"\n        },\n        {\n          \"dmxRange\": [151, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 8\"\n        },\n        {\n          \"dmxRange\": [173, 193],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 9\"\n        },\n        {\n          \"dmxRange\": [194, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 10\"\n        },\n        {\n          \"dmxRange\": [215, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 11\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 12\"\n        }\n      ]\n    },\n    \"Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 17],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [18, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [35, 51],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [52, 68],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [69, 85],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [86, 102],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [103, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"],\n          \"comment\": \"Red + White\"\n        },\n        {\n          \"dmxRange\": [120, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [137, 153],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Green + White\"\n        },\n        {\n          \"dmxRange\": [154, 170],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [171, 187],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [188, 204],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Red + Green + White\"\n        },\n        {\n          \"dmxRange\": [205, 221],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Blue + White\"\n        },\n        {\n          \"dmxRange\": [222, 238],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [239, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + White\"\n        }\n      ]\n    },\n    \"Chase Speed\": {\n      \"defaultValue\": 128,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Red\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Green\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Blue\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"White\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4 channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Function\",\n        \"Pattern / Chase\",\n        \"Color / Chase Speed\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"256 channel\",\n      \"shortName\": \"256ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/revo-burst.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Revo Burst\",\n  \"shortName\": \"ADJRevoBurst\",\n  \"categories\": [\"Flower\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-01-24\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://adjmedia.s3-website-eu-west-1.amazonaws.com/manuals/Revo%20Burst%20LO.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wRo1JwMHJQE\",\n      \"https://www.youtube.com/watch?v=HnwEm7ExALw\"\n    ],\n    \"other\": [\n      \"https://www.qlcplus.org/forum/viewtopic.php?f=6&t=11824\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [216, 239, 312],\n    \"weight\": 3.2,\n    \"power\": 20,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"RGBW LEDs\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [    null, null, \"Beam 6\", null,     null],\n        [\"Beam 5\", null,     null, null, \"Beam 7\"],\n        [    null, null, \"Beam 1\", null,     null],\n        [\"Beam 4\", null,     null, null, \"Beam 2\"],\n        [    null, null, \"Beam 3\", null,     null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"All Beams\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern\",\n          \"switchChannels\": {\n            \"Strobe / Chase Speed\": \"Pattern Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase\",\n          \"switchChannels\": {\n            \"Strobe / Chase Speed\": \"Chase Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Chase Speed\": \"Pattern Strobe\"\n          }\n        }\n      ]\n    },\n    \"Pattern Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Strobe off\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Chase Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Pattern / Chase $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 1\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 2\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 3\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 4\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 5\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 6\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 7\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 8\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 9\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 10\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 11\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 12\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 13\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 14\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern / Chase 15\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Pattern / Chase All Beams\",\n        \"Strobe / Chase Speed\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Mode\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Pattern / Chase $pixelKey\"\n          ]\n        },\n        \"Strobe / Chase Speed\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/revo-sweep.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Revo Sweep\",\n  \"shortName\": \"ADJRevoSweep\",\n  \"categories\": [\"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-06\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\"http://adjmedia.s3-website-eu-west-1.amazonaws.com/manuals/revo_sweep.pdf\"],\n    \"video\": [\"https://www.youtube.com/watch?v=FnVigOaqr4E\"]\n  },\n  \"physical\": {\n    \"dimensions\": [317, 182, 250],\n    \"weight\": 2,\n    \"power\": 13,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [116, 116]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [7, 1, 1]\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color\",\n          \"switchChannels\": {\n            \"Color / Chase\": \"Color\",\n            \"Strobe / Chase Speed\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase\",\n          \"switchChannels\": {\n            \"Color / Chase\": \"Chase\",\n            \"Strobe / Chase Speed\": \"Chase Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color / Chase\": \"Color\",\n            \"Strobe / Chase Speed\": \"Strobe\"\n          }\n        }\n      ]\n    },\n    \"Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"Which colors can be selected in this channel?\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\"\n        }\n      ]\n    },\n    \"Chase\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 13\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 14\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 15\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 16\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 17\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 18\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 19\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 20\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 21\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 22\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 23\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 24\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 25\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Chase Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Color / Chase\",\n        \"Strobe / Chase Speed\"\n      ]\n    },\n    {\n      \"name\": \"28-channel\",\n      \"shortName\": \"28ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/saber-spot-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Saber Spot RGBW\",\n  \"shortName\": \"SaberSpotRGBW\",\n  \"categories\": [\"Color Changer\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Voyo\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-11-01\",\n    \"lastModifyDate\": \"2018-11-01\"\n  },\n  \"comment\": \"The Saber Spot RGBW is a compact Pinspot with smooth RGBW color mixing from one 15W 4-in-1 Quad LED. It has a built-in ACL lens that produces a razor sharp 4-degree beam angle.\",\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/10530/Saber%20Spot%20RGBW%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/saber-spot-rgbw\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=lkNhECfzFqo\",\n      \"https://www.youtube.com/watch?v=j3cX955wyfs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [170, 135, 215],\n    \"weight\": 1.2,\n    \"power\": 14,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"15W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default dimmer curve setting\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7affef\"],\n          \"comment\": \"Color 1\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7affba\"],\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#76ff91\"],\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#97ff7d\"],\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b6ff76\"],\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e7ff7d\"],\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fff676\"],\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd473\"],\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbb76\"],\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9a73\"],\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8575\"],\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6f74\"],\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7da4\"],\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff88ca\"],\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8bf1\"],\n          \"comment\": \"Color 15\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f388ff\"],\n          \"comment\": \"Color 16\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d382ff\"],\n          \"comment\": \"Color 17\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b185ff\"],\n          \"comment\": \"Color 18\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8876ff\"],\n          \"comment\": \"Color 19\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7688ff\"],\n          \"comment\": \"Color 20\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6aaaff\"],\n          \"comment\": \"Color 21\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#76d1ff\"],\n          \"comment\": \"Color 22\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#76efff\"],\n          \"comment\": \"Color 23\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c1ffb8\"],\n          \"comment\": \"Color 24\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffdbf\"],\n          \"comment\": \"Color 25\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffccba\"],\n          \"comment\": \"Color 26\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb3d2\"],\n          \"comment\": \"Color 27\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbafc\"],\n          \"comment\": \"Color 28\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bcb3ff\"],\n          \"comment\": \"Color 29\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8f48ff\"],\n          \"comment\": \"Color 30\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b3c7ff\"],\n          \"comment\": \"Color 31\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Color 32\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffce8f\"],\n          \"comment\": \"Color 33\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#feb199\"],\n          \"comment\": \"Color 34\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fec08a\"],\n          \"comment\": \"Color 35\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fea562\"],\n          \"comment\": \"Color 36\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fe7900\"],\n          \"comment\": \"Color 37\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b01100\"],\n          \"comment\": \"Color 38\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#60000b\"],\n          \"comment\": \"Color 39\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ea8bab\"],\n          \"comment\": \"Color 40\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e00561\"],\n          \"comment\": \"Color 41\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#af4dad\"],\n          \"comment\": \"Color 42\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7782c7\"],\n          \"comment\": \"Color 43\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#93a4d4\"],\n          \"comment\": \"Color 44\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5802a3\"],\n          \"comment\": \"Color 45\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002656\"],\n          \"comment\": \"Color 46\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#008ed0\"],\n          \"comment\": \"Color 47\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#3494d1\"],\n          \"comment\": \"Color 48\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0186c9\"],\n          \"comment\": \"Color 49\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0091d4\"],\n          \"comment\": \"Color 50\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0079c0\"],\n          \"comment\": \"Color 51\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0081b8\"],\n          \"comment\": \"Color 52\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#005373\"],\n          \"comment\": \"Color 53\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0061a6\"],\n          \"comment\": \"Color 54\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0164a7\"],\n          \"comment\": \"Color 55\"\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002856\"],\n          \"comment\": \"Color 56\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d1dbb6\"],\n          \"comment\": \"Color 57\"\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2aa555\"],\n          \"comment\": \"Color 58\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002e23\"],\n          \"comment\": \"Color 59\"\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#086bde\"],\n          \"comment\": \"Color 60\"\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6b9ce7\"],\n          \"comment\": \"Color 61\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a5c6f7\"],\n          \"comment\": \"Color 62\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000bd\"],\n          \"comment\": \"Color 63\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Color 64\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [161, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [181, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [221, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [241, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gradient\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"fast\",\n        \"parameterEnd\": \"slow\",\n        \"comment\": \"Program fade\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"HSI\",\n      \"shortName\": \"hsi\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"RGBW\",\n      \"shortName\": \"rgbw\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"HSI Dimmer Curve\",\n      \"shortName\": \"hsi-curve\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"RGBWD\",\n      \"shortName\": \"rgbwd\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"RGBWD Strobe\",\n      \"shortName\": \"rgbw-strb\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"RGBWD fine\",\n      \"shortName\": \"rgbwd-fine\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBWD fine Strobe\",\n      \"shortName\": \"rgbwd-fine-strb\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"RGBW fine\",\n      \"shortName\": \"rgbw-fine\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI Programs\",\n      \"shortName\": \"hsi-prg\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Color Macros\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"RGBW Programs\",\n      \"shortName\": \"rgbw-prg\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Color Macros\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"RGBW Programs fine\",\n      \"shortName\": \"rgbw-prg-fine\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/starburst.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Starbust\",\n  \"shortName\": \"ADJStarburst\",\n  \"categories\": [\"Effect\", \"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Gerard Fontanillas\"],\n    \"createDate\": \"2019-03-03\",\n    \"lastModifyDate\": \"2019-03-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/8787/ADJ%20Starburst%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/starburst\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=SetHSmR7J6c\",\n      \"https://www.youtube.com/watch?v=haRjymezIig\",\n      \"https://www.youtube.com/watch?v=WXHROB4soLs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [318, 412.5, 318],\n    \"weight\": 3.65,\n    \"power\": 55,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 15W RGBWAUV LEDs\"\n    },\n    \"lens\": {\n      \"name\": \"34 beams\",\n      \"degreesMinMax\": [1, 1]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 8,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Rotation\": {\n      \"defaultValue\": 143,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [31, 140],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [146, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 205],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which color macros can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [206, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 55],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [56, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [76, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red CW\"\n        },\n        {\n          \"dmxRange\": [106, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blue CCW\"\n        },\n        {\n          \"dmxRange\": [136, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"7-color change CW\"\n        },\n        {\n          \"dmxRange\": [166, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"7-color change CCW\"\n        },\n        {\n          \"dmxRange\": [196, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"7-color change with strobe CW\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"7-color change with strobe CCW\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 85],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [86, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Rotation\",\n        \"Color Macros\",\n        \"Programs\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/stinger-ii.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stinger II\",\n  \"shortName\": \"ADJStinger2\",\n  \"categories\": [\"Laser\", \"Flower\", \"Strobe\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-04-07\",\n    \"lastModifyDate\": \"2019-04-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/8885/ADJ%20Stinger%20II%20-%20User%20Manual%202023-08-11.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/stinger-ii\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=XCDmUI576hg\",\n      \"https://www.youtube.com/watch?v=aC-e9Qma0fU\",\n      \"https://www.youtube.com/watch?v=YECVi23sda8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [230.5, 304, 248],\n    \"weight\": 5,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"6x 5W RGBWAUV and 8x 3W UV LEDs; red and green laser (4.9mW)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Show Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 1\"\n        },\n        {\n          \"dmxRange\": [45, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 2\"\n        },\n        {\n          \"dmxRange\": [80, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 3\"\n        },\n        {\n          \"dmxRange\": [115, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 4\"\n        },\n        {\n          \"dmxRange\": [150, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 5\"\n        },\n        {\n          \"dmxRange\": [185, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 6\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random show\"\n        }\n      ]\n    },\n    \"Show Speed / Sound Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 247],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Color Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 198],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [199, 225],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"2\"\n        }\n      ]\n    },\n    \"LED Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 134],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [135, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"UV chase\"\n        }\n      ]\n    },\n    \"UV Chase Speed / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"strobing\"\n        }\n      ]\n    },\n    \"Lasers\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [50, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [90, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + green\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [130, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + green flicker\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [170, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + red flicker\",\n          \"colors\": [\"#00ff00\", \"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + green flicker sync\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + green flicker alternate\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"]\n        }\n      ]\n    },\n    \"Laser Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"LED Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Laser Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Laser patterns\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern chase\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Show Mode\",\n        \"Show Speed / Sound Mode\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Show Mode\",\n        \"Color Macro\",\n        \"LED Strobe\",\n        \"UV\",\n        \"UV Chase Speed / Strobe\",\n        \"Lasers\",\n        \"Laser Strobe\",\n        \"LED Rotation\",\n        \"Laser Rotation\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/stinger-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stinger Spot\",\n  \"shortName\": \"ADJStingerSpot\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"unk\", \"Felix Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-04-02\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/11167/ADJ%20Stinger%20Spot%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/stinger-spot\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=nOYqH2oVWZg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [174, 273, 145],\n    \"weight\": 3,\n    \"power\": 36,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"10W white LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff9900\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#0099ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"210deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [15, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [36, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [43, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [50, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [57, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Split Colors\",\n          \"helpWanted\": \"Which split colors can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 8,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Movement Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with pan/tilt\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout with pan/tilt\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with color change\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout with color change\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with gobo change\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout with gobo change\"\n        },\n        {\n          \"dmxRange\": [130, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Dimmer Curves\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default unit curve\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Movement Speed\",\n        \"Function\",\n        \"Dimmer Curves\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Movement Speed\",\n        \"Function\",\n        \"Dimmer Curves\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/ultra-hex-bar-12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Ultra Hex Bar 12\",\n  \"shortName\": \"ADJUHB12\",\n  \"categories\": [\"Color Changer\", \"Strobe\", \"Pixel Bar\"],\n  \"meta\": {\n    \"authors\": [\"Silvère Oriat\", \"Flo Edelmann\"],\n    \"createDate\": \"2026-01-28\",\n    \"lastModifyDate\": \"2026-01-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/8759/ADJ%20Ultra%20Hex%20Bar%2012%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/products/ultra-hex-bar-12\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1020, 70, 122],\n    \"weight\": 4.74,\n    \"power\": 90,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED RGBWA + UV\",\n      \"lumens\": 2438\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/6\": [\"1\", \"2\"],\n      \"2/6\": [\"3\", \"4\"],\n      \"3/6\": [\"5\", \"6\"],\n      \"4/6\": [\"7\", \"8\"],\n      \"5/6\": [\"9\", \"10\"],\n      \"6/6\": [\"11\", \"12\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ff8800\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#440088\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W\",\n          \"colors\": [\"#ff6666\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+A\",\n          \"colors\": [\"#ff8866\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+UV\",\n          \"colors\": [\"#ff0044\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W\",\n          \"colors\": [\"#66ff66\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+A\",\n          \"colors\": [\"#88ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+UV\",\n          \"colors\": [\"#44ff88\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W\",\n          \"colors\": [\"#8888ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+A\",\n          \"colors\": [\"#8844ff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+UV\",\n          \"colors\": [\"#4400ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+A\",\n          \"colors\": [\"#ffffaa\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+UV\",\n          \"colors\": [\"#ffccff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A+UV\",\n          \"colors\": [\"#ffaa88\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B\",\n          \"colors\": [\"#dddddd\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W\",\n          \"colors\": [\"#ffffdd\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+A\",\n          \"colors\": [\"#ffffdd\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+UV\",\n          \"colors\": [\"#ffffdd\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W\",\n          \"colors\": [\"#ffddff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+A\",\n          \"colors\": [\"#ffffdd\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+UV\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+A\",\n          \"colors\": [\"#ffdddd\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+UV\",\n          \"colors\": [\"#ffddff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+A+UV\",\n          \"colors\": [\"#ffffee\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W\",\n          \"colors\": [\"#ddffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+A\",\n          \"colors\": [\"#ccffdd\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+UV\",\n          \"colors\": [\"#44ddff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+A\",\n          \"colors\": [\"#88ffdd\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+UV\",\n          \"colors\": [\"#ddffff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+A+UV\",\n          \"colors\": [\"#88ffdd\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+A\",\n          \"colors\": [\"#dd88ff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+UV\",\n          \"colors\": [\"#aaaaff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+A+UV\",\n          \"colors\": [\"#ddaaff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W+A+UV\",\n          \"colors\": [\"#ccaadd\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W\",\n          \"colors\": [\"#eeeeee\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+A\",\n          \"colors\": [\"#ffeedd\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+UV\",\n          \"colors\": [\"#ffeeff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+A\",\n          \"colors\": [\"#ffeedd\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+UV\",\n          \"colors\": [\"#ffdddd\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+A+UV\",\n          \"colors\": [\"#eeffdd\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+W+A\",\n          \"colors\": [\"#ffddff\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+UV\",\n          \"colors\": [\"#ffffee\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+B+A+UV\",\n          \"colors\": [\"#ffaaff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+W+A+UV\",\n          \"colors\": [\"#ffeeee\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+A\",\n          \"colors\": [\"#ddffff\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+UV\",\n          \"colors\": [\"#ccffff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+A+UV\",\n          \"colors\": [\"#bbeeff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+W+A+UV\",\n          \"colors\": [\"#ddffaa\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B+W+A+UV\",\n          \"colors\": [\"#ffeeff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+A\",\n          \"colors\": [\"#fffefe\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+UV\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+A+UV\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+W+A+UV\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+A+UV\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G+B+W+A+UV\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R+G+B+W+A+UV\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [47, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [58, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [69, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [113, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [124, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [135, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [146, 156],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [157, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 178],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [179, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [212, 222],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [223, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Programs\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default dimmer setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        \"UV Master\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        \"UV Master\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        \"UV Master\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        \"UV Master\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Mode\"\n      ]\n    },\n    {\n      \"name\": \"36-channel\",\n      \"shortName\": \"36ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\",\n            \"UV $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/uv-eco-bar.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"UV Eco Bar\",\n  \"shortName\": \"uv-eco-bar\",\n  \"categories\": [\"Other\"],\n  \"meta\": {\n    \"authors\": [\"Nikita\"],\n    \"createDate\": \"2024-09-11\",\n    \"lastModifyDate\": \"2024-09-11\"\n  },\n  \"comment\": \"18x3W UV LEDs\",\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/6914/ADJ%20Eco%20UV%20Bar%20DMX%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/eco-uv-bar-dmx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=mEH-cVF_iB4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1000, 60, 115],\n    \"weight\": 2.4,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobing\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 1\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 2\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 3\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 4\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Delay Mode Control (works in conjunction with Delay Mode in the main settings menu)\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobing\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/vbar-pak.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"VBar Pak\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-04-03\",\n    \"lastModifyDate\": \"2022-04-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/8659/vbar_pak.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/vbar-pak\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=bah_MlTImIg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [560, 63, 90],\n    \"weight\": 1.7,\n    \"power\": 21,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5× 4W RGBA LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red & Green\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red & Blue\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red & Amber\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green & Blue\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green & Amber\",\n          \"colors\": [\"#9fff00\"]\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue & Amber\",\n          \"colors\": [\"#00ff95\"]\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red & Green & Blue\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red & Green & Amber\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red & Blue & Amber\",\n          \"colors\": [\"#ff0020\"]\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green & Blue & Amber\",\n          \"colors\": [\"#20ff00\"]\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red & Green & Blue & Amber\",\n          \"colors\": [\"#ffda6b\"]\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer mode\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Strobe\",\n            \"Color Macros & Modes\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color macro mode\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Strobe\",\n            \"Color Macros & Modes\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color change mode\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Color Macros & Modes\": \"Color Change Programs\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color fade mode\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\",\n            \"Color Macros & Modes\": \"Color Fade Programs\"\n          }\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\",\n            \"Color Macros & Modes\": \"Sound Active Programs\"\n          }\n        }\n      ]\n    },\n    \"Color Change Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color change 16\"\n        }\n      ]\n    },\n    \"Color Fade Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 14\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 15\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Color fade 16\"\n        }\n      ]\n    },\n    \"Sound Active Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode 16\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe / Program Speed / Sound Sensitivity\",\n        \"Mode\",\n        \"Color Macros & Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/vizi-q-wash7.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Vizi Q Wash7\",\n  \"shortName\": \"Q7\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Rey Victor\", \"Luke Nelson\"],\n    \"createDate\": \"2023-04-25\",\n    \"lastModifyDate\": \"2023-04-25\"\n  },\n  \"comment\": \"The Vizi Q Wash7 is a 280W professional moving head wash fixture with variable zoom (5 ~ 55-degrees) and seven 40W Quad (RGBW) LEDs. At 280W, this fixture offers very powerful 5-degree beams or brilliant 55-degree washes of color. WiFLY wireless DMX on-board.\",\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/10532/ADJ%20VIZI%20Q%20WASH7%20-%20USER%20MANUAL%20.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/vizi-q-wash7\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=EHeTZ_G_8zM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [284.4, 411.7, 202],\n    \"weight\": 8.5,\n    \"power\": 280,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 58]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, \"O1\", null, \"O2\", null],\n        [\"O3\", null, \"C\", null, \"O4\"],\n        [null, \"O5\", null, \"O6\", null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"All\": \"all\",\n      \"Center\": { \"name\": [\"C\"] },\n      \"Outer\": { \"name\": [\"^O\\\\d+$\"] }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"-160deg\",\n        \"angleEnd\": \"160deg\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": \"0%\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7affef\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7affba\"],\n          \"comment\": \"Aquamarine\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#76ff91\"],\n          \"comment\": \"Malachite Green\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#97ff7d\"],\n          \"comment\": \"Mint Green\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b6ff76\"],\n          \"comment\": \"Reef\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e7ff7d\"],\n          \"comment\": \"Honeysuckle\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fff676\"],\n          \"comment\": \"Sunny\"\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd473\"],\n          \"comment\": \"Dandelion\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbb76\"],\n          \"comment\": \"Apricot\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9a73\"],\n          \"comment\": \"Light Salmon\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8575\"],\n          \"comment\": \"Salmon\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6f74\"],\n          \"comment\": \"Begonia\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7da4\"],\n          \"comment\": \"Tickle Me Pink\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff88ca\"],\n          \"comment\": \"Princess Perfume\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8bf1\"],\n          \"comment\": \"Light Fuchsia Pink\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f388ff\"],\n          \"comment\": \"Fuchsia Pink\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d382ff\"],\n          \"comment\": \"Heliotrope\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b185ff\"],\n          \"comment\": \"Pale Violet\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8876ff\"],\n          \"comment\": \"Violet Blue\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7688ff\"],\n          \"comment\": \"Cornflower Blue\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6aaaff\"],\n          \"comment\": \"Sky Blue\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#76d1ff\"],\n          \"comment\": \"Maya Blue\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#76efff\"],\n          \"comment\": \"Star Explosion Blue\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c1ffb8\"],\n          \"comment\": \"Tea Green\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffdbf\"],\n          \"comment\": \"Very Pale Yellow\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffccba\"],\n          \"comment\": \"Apricot\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb3d2\"],\n          \"comment\": \"Lavender Pink\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbafc\"],\n          \"comment\": \"Brilliant Lavender\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bcb3ff\"],\n          \"comment\": \"Vodka\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8f48ff\"],\n          \"comment\": \"Lavender Indigo\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b3c7ff\"],\n          \"comment\": \"Pale Cornflower Blue\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffce8f\"],\n          \"comment\": \"Peach Orange\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#feb199\"],\n          \"comment\": \"Mona Lisa\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fec08a\"],\n          \"comment\": \"Chardonnayapprox\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fea562\"],\n          \"comment\": \"Atomic Tangerine\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fe7900\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b01100\"],\n          \"comment\": \"Bright Red\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#60000b\"],\n          \"comment\": \"Rosewood\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ea8bab\"],\n          \"comment\": \"Carissma\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e00561\"],\n          \"comment\": \"Razzmatazz\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#af4dad\"],\n          \"comment\": \"Fuchsia Pink\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7782c7\"],\n          \"comment\": \"Blue Marguerite\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#93a4d4\"],\n          \"comment\": \"Polo Blue\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5802a3\"],\n          \"comment\": \"Purple\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002656\"],\n          \"comment\": \"Prussian Blue\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#008ed0\"],\n          \"comment\": \"Lochmara\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#3494d1\"],\n          \"comment\": \"Curious Blue\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0186c9\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0091d4\"],\n          \"comment\": \"Cerulean\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0079c0\"],\n          \"comment\": \"Ocean Boat Blue\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0081b8\"],\n          \"comment\": \"Star Command Blue\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#005373\"],\n          \"comment\": \"Dark Cerulean\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0061a6\"],\n          \"comment\": \"Endeavour\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0164a7\"],\n          \"comment\": \"Medium Persian Blue\"\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002856\"],\n          \"comment\": \"Prussian Blue\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d1dbb6\"],\n          \"comment\": \"Green Mist\"\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2aa555\"],\n          \"comment\": \"Eucalyptus\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002e23\"],\n          \"comment\": \"Burnham\"\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#086bde\"],\n          \"comment\": \"Science Blue\"\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6b9ce7\"],\n          \"comment\": \"Cornflower Blue\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a5c6f7\"],\n          \"comment\": \"Perano\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000bd\"],\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 48,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"7deg\",\n        \"angleEnd\": \"58deg\"\n      }\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": \"0%\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [161, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [181, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [221, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [241, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"instant\",\n          \"helpWanted\": \"What does fade \\\"Normal\\\" mean in the manual? Is it instant (no fade)?\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"EffectDuration\",\n          \"durationStart\": \"short\",\n          \"durationEnd\": \"long\",\n          \"helpWanted\": \"Is this fade \\\"short to long\\\" or \\\"long to short\\\" like mentioned in the manual?\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default Dimmer Setting\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": \"100%\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by movement\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Maintenance Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motor reset\"\n        },\n        {\n          \"dmxRange\": [85, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Internal Program 1\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Internal Program 2\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Internal Program 3\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Internal Program 4\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Internal Program 5\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Internal Program 6\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Internal Program 7\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"17-channel Basic\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Red All\",\n        \"Green All\",\n        \"Blue All\",\n        \"White All\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Curve\",\n        \"Pan/Tilt Speed\",\n        \"Maintenance Functions\"\n      ]\n    },\n    {\n      \"name\": \"19-channel Standard\",\n      \"shortName\": \"19ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red All\",\n        \"Green All\",\n        \"Blue All\",\n        \"White All\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Curve\",\n        \"Pan/Tilt Speed\",\n        \"Maintenance Functions\"\n      ]\n    },\n    {\n      \"name\": \"23-channel Extended\",\n      \"shortName\": \"23ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red Center\",\n        \"Green Center\",\n        \"Blue Center\",\n        \"White Center\",\n        \"Red Outer\",\n        \"Green Outer\",\n        \"Blue Outer\",\n        \"White Outer\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Program Fade\",\n        \"Dimmer Curve\",\n        \"Pan/Tilt Speed\",\n        \"Maintenance Functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/vizi-spot-led-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Vizi Spot LED Pro\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Bram Nauta\"],\n    \"createDate\": \"2018-07-19\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3-us-west-1.amazonaws.com/ItemRelatedFiles/7080/vizi_spot_led_pro.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=gxV-Hpqi2kc\",\n      \"https://www.youtube.com/watch?v=XQBC1wotMAQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [303, 442, 253],\n    \"weight\": 10.5,\n    \"power\": 130,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 1480\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#800080\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffa500\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#3e0694\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [15, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [30, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [45, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [60, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [75, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism/Gobo Macro\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Prism\",\n          \"comment\": \"3-Facet\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Prism\",\n          \"comment\": \"Trapezoid\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 1\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 2\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 3\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 4\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 5\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 6\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 7\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 8\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 9\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 10\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 11\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 12\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 13\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 14\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Macro 16\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"defaultValue\": 127,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Shutter/Strobe\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"in sequences\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while wheel is changing\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Reset & Internal Programs\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Change Normal\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Change To Any Position\"\n        },\n        {\n          \"dmxRange\": [40, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All Motor Reset\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"P/T Motor Reset\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Motor Reset\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo Motor Reset\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Other Motor Reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 1\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 2\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 3\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 4\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 5\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 6\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 7\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Program\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism/Gobo Macro\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Shutter/Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Reset & Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism/Gobo Macro\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Shutter/Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Reset & Internal Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/american-dj/xs-400.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"XS 400\",\n  \"shortName\": \"XS400\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-09-04\",\n    \"lastModifyDate\": \"2019-05-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://adjmedia.s3-website-eu-west-1.amazonaws.com/manuals/XS%20400.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.eu/xs-400\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Don23z-XN-s\",\n      \"https://www.youtube.com/watch?v=AjbBAu8UHW8\",\n      \"https://www.youtube.com/watch?v=EpWMiggfdBM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [169.9, 284.5, 123.6],\n    \"weight\": 2.5,\n    \"power\": 45,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4x 10W RGBW LEDs\",\n      \"lumens\": 454\n    },\n    \"lens\": {\n      \"degreesMinMax\": [5, 5]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Tilt Continuous Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 55],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [56, 127],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 199],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Tilt Continuous Rotation Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Is this pan rotation? If not, is it correct that channel 'Tilt Continuous Rotation' only sets direction and this channel the rotation speed?\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Macros & Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [81, 123],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [124, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color mix\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"How does this differ from the other color effects?\"\n        },\n        {\n          \"dmxRange\": [167, 209],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color change\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"How does this differ from the other color effects?\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Strobing\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [140, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"Is the strobe speed controllable here?\"\n        },\n        {\n          \"dmxRange\": [190, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"Is the strobe speed controllable here?\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [41, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [66, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [91, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [116, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [141, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [166, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [191, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [216, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random program playing 5 times each\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random program 2min each\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pan / Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with Pan / Tilt movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with RGBW value change\"\n        },\n        {\n          \"dmxRange\": [100, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default setting\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Tilt Continuous Rotation\",\n        \"Tilt Continuous Rotation Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros & Effects\",\n        \"Strobing\",\n        \"Master Dimmer\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Pan / Tilt Speed\",\n        \"Special Functions\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Tilt Continuous Rotation\",\n        \"Tilt Continuous Rotation Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros & Effects\",\n        \"Strobing\",\n        \"Master Dimmer\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Pan / Tilt Speed\",\n        \"Special Functions\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ape-labs/lightcan.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LightCan\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Gloryfire\"],\n    \"createDate\": \"2019-05-30\",\n    \"lastModifyDate\": \"2019-05-30\"\n  },\n  \"comment\": \"Only controllable via Wireless DMX (W-APE).\",\n  \"links\": {\n    \"manual\": [\n      \"https://bklumitec.com/out/media/106619_BA_D_E_Light_Can.pdf\"\n    ],\n    \"productPage\": [\n      \"https://apelabs.com/produkt/lightcan-roadbag/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=323kJeW-KT0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [55, 136, 55],\n    \"weight\": 0.39,\n    \"bulb\": {\n      \"type\": \"15W RGBW LED\"\n    },\n    \"lens\": {\n      \"name\": \"Effect lens\",\n      \"degreesMinMax\": [65, 65]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [6, 11],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [12, 17],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [18, 23],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [24, 29],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Lime\"\n        },\n        {\n          \"dmxRange\": [30, 35],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [36, 41],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [42, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Cyan/Blue\"\n        },\n        {\n          \"dmxRange\": [48, 53],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [54, 59],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Blue/Magenta\"\n        },\n        {\n          \"dmxRange\": [60, 65],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [66, 71],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Red pastel\"\n        },\n        {\n          \"dmxRange\": [72, 77],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Green pastel\"\n        },\n        {\n          \"dmxRange\": [78, 83],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Blue pastel\"\n        },\n        {\n          \"dmxRange\": [84, 89],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Blue > Red\"\n        },\n        {\n          \"dmxRange\": [90, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Magenta > White\"\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"White > Blue\"\n        },\n        {\n          \"dmxRange\": [102, 107],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Red pastel > Green pastel > Blue pastel\"\n        },\n        {\n          \"dmxRange\": [108, 113],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Yellow > Magenta > Blue\"\n        },\n        {\n          \"dmxRange\": [114, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Rainbow\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [134, 139],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [140, 145],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [146, 151],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [152, 157],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Lime\"\n        },\n        {\n          \"dmxRange\": [158, 163],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [164, 169],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [170, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Cyan/Blue\"\n        },\n        {\n          \"dmxRange\": [176, 181],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [182, 187],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Blue/Magenta\"\n        },\n        {\n          \"dmxRange\": [188, 193],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [194, 199],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Red pastel\"\n        },\n        {\n          \"dmxRange\": [200, 205],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Green pastel\"\n        },\n        {\n          \"dmxRange\": [206, 211],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Blue pastel\"\n        },\n        {\n          \"dmxRange\": [212, 217],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Blue > Red\"\n        },\n        {\n          \"dmxRange\": [218, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Magenta > White\"\n        },\n        {\n          \"dmxRange\": [224, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"White > Blue\"\n        },\n        {\n          \"dmxRange\": [230, 235],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Red pastel > Green pastel > Blue pastel\"\n        },\n        {\n          \"dmxRange\": [236, 241],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Yellow > Magenta > Blue\"\n        },\n        {\n          \"dmxRange\": [242, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Rainbow\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-Channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"4-Channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"8-Channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/aputure/ls-1200d-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LS 1200D Pro\",\n  \"categories\": [\"Dimmer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2022-09-24\",\n    \"lastModifyDate\": \"2022-09-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://aputure.com/wp-content/uploads/2022/06/LS1200D-Pro-DMX-Profile-Specification-V1.0-.pdf\"\n    ],\n    \"productPage\": [\n      \"https://aputure.com/products/ls-1200d-pro/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [332, 231, 216],\n    \"weight\": 7.6,\n    \"power\": 1200,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"fineChannelAliases\": [\"Intensity fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Faulty bulb\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Explosion\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Frequency\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Generic\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Mode Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Manual Mode\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"FX Mode\"\n        }\n      ]\n    },\n    \"Lightning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Stop\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Loop\"\n        }\n      ]\n    },\n    \"Explosion\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Stop\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Lighting 8-bit\",\n      \"shortName\": \"P1\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Effect 8-bit\",\n      \"shortName\": \"P2\",\n      \"channels\": [\n        \"Intensity\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    },\n    {\n      \"name\": \"Lighting & Effect 8-bit\",\n      \"shortName\": \"P3\",\n      \"channels\": [\n        \"Intensity\",\n        \"Mode Selection\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    },\n    {\n      \"name\": \"Lighting 16-bit\",\n      \"shortName\": \"P4\",\n      \"channels\": [\n        \"Intensity\",\n        \"Intensity fine\"\n      ]\n    },\n    {\n      \"name\": \"Effect 16-bit\",\n      \"shortName\": \"P5\",\n      \"channels\": [\n        \"Intensity\",\n        \"Intensity fine\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    },\n    {\n      \"name\": \"Lighting & Effect 16-bit\",\n      \"shortName\": \"P6\",\n      \"channels\": [\n        \"Intensity\",\n        \"Intensity fine\",\n        \"Mode Selection\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/aputure/ls-300x.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LS 300x\",\n  \"categories\": [\"Dimmer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Peter Zuiderent\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-05-07\",\n    \"lastModifyDate\": \"2022-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://aputure.com/wp-content/uploads/2020/04/LS_300x-Product_Manual_EN.pdf\"\n    ],\n    \"productPage\": [\n      \"https://aputure.com/products/ls-300x/\"\n    ],\n    \"other\": [\n      \"https://aputure.com/wp-content/uploads/2021/02/LS-300x-DMX-Table.xlsx\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [298, 216, 345],\n    \"weight\": 11.4,\n    \"power\": 300,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 195],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2700K\",\n          \"colorTemperatureEnd\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [196, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Frequency Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Generic\",\n          \"comment\": \"R\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Mode Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Manual Mode\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"FX Mode\"\n        }\n      ]\n    },\n    \"FX Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Faulty Bulb\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Explosion\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [180, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Start Trigger\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Start Point\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Single Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Cycle Mode (Lightning)\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Default\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT Control\",\n        \"Frequency Control\",\n        \"Mode Selection\",\n        \"FX Control\",\n        \"Start Trigger\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/aputure/ls-600d-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LS 600D Pro\",\n  \"categories\": [\"Dimmer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2022-09-24\",\n    \"lastModifyDate\": \"2022-09-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://aputure.com/wp-content/uploads/2022/06/LS-600d-Pro-DMX-Profile-Specification-V1.0-.pdf\"\n    ],\n    \"productPage\": [\n      \"https://aputure.com/products/ls-600d-pro/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [308, 156, 150],\n    \"weight\": 4.6,\n    \"power\": 600,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Faulty bulb\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Explosion\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Frequency\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Generic\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Mode Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Manual Mode\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"FX Mode\"\n        }\n      ]\n    },\n    \"Lightning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Stop\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Loop\"\n        }\n      ]\n    },\n    \"Explosion\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Stop\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Lighting & Effect 8-bit\",\n      \"channels\": [\n        \"Intensity\",\n        \"Mode Selection\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/aputure/ls-600d.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LS 600D\",\n  \"categories\": [\"Dimmer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2022-09-24\",\n    \"lastModifyDate\": \"2022-09-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://aputure.com/wp-content/uploads/2022/06/LS-600d-DMX-Profile-Specification-V1.0-.pdf\"\n    ],\n    \"productPage\": [\n      \"https://aputure.com/products/ls-600d/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [308, 156, 121],\n    \"weight\": 4.7,\n    \"power\": 600,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Faulty bulb\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Explosion\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Frequency\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Generic\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Mode Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Manual Mode\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"FX Mode\"\n        }\n      ]\n    },\n    \"Lightning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Stop\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Loop\"\n        }\n      ]\n    },\n    \"Explosion\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Stop\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Lighting 8-bit\",\n      \"shortName\": \"P1\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Effect 8-bit\",\n      \"shortName\": \"P2\",\n      \"channels\": [\n        \"Intensity\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    },\n    {\n      \"name\": \"Lighting & Effect 8-bit\",\n      \"shortName\": \"P3\",\n      \"channels\": [\n        \"Intensity\",\n        \"Mode Selection\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/aputure/ls-600x-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LS 600X Pro\",\n  \"categories\": [\"Dimmer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2022-09-24\",\n    \"lastModifyDate\": \"2022-09-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://aputure.com/wp-content/uploads/2022/06/LS600X-Pro-DMX-Profile-Specification-V1.0-.pdf\"\n    ],\n    \"productPage\": [\n      \"https://aputure.com/products/ls-600x-pro/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [302, 147, 149],\n    \"weight\": 5.2,\n    \"power\": 600,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2700K\",\n        \"colorTemperatureEnd\": \"6500K\"\n      }\n    },\n    \"Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Faulty bulb\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Explosion\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Frequency\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"10\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Generic\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Mode Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Manual Mode\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"FX Mode\"\n        }\n      ]\n    },\n    \"Lightning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Stop\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Loop\"\n        }\n      ]\n    },\n    \"Explosion\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Stop\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Trigger\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Lighting 8-bit\",\n      \"shortName\": \"P1\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"Effects 8-bit\",\n      \"shortName\": \"P2\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    },\n    {\n      \"name\": \"Lighting & Effects 8-bit\",\n      \"shortName\": \"P3\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Mode Selection\",\n        \"Effects\",\n        \"Frequency\",\n        \"Lightning\",\n        \"Explosion\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/aputure/nova-p300c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Nova P300c\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Peter Zuiderent\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-05-07\",\n    \"lastModifyDate\": \"2022-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://aputure.com/wp-content/uploads/2020/06/Nova_P300c_Manual_20200722-EN.pdf\"\n    ],\n    \"productPage\": [\n      \"https://aputure.com/products/nova-p300c/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=qr-QiRpwijI\"\n    ],\n    \"other\": [\n      \"https://aputure.com/wp-content/uploads/2021/02/Nova-P300c-DMX-Table_2020-12-09.xlsx\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [562, 457, 166],\n    \"weight\": 10.35,\n    \"power\": 300,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2000K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Gel CCT\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [127, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"CCT <-> RGB\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"crossfade to color\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Green/Magenta Point\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"Generic\",\n          \"comment\": \"-1.0\"\n        },\n        {\n          \"dmxRange\": [12, 120],\n          \"type\": \"Generic\",\n          \"comment\": \"-0.9 … -0.1\"\n        },\n        {\n          \"dmxRange\": [121, 132],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [133, 241],\n          \"type\": \"Generic\",\n          \"comment\": \"0.1 … 0.9\"\n        },\n        {\n          \"dmxRange\": [242, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"1.0\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"1° … 360°\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"CCT <-> HSI\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Cross Fade To Color\"\n      }\n    },\n    \"Gel R/L\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"L\"\n        },\n        {\n          \"dmxRange\": [30, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"R\"\n        },\n        {\n          \"dmxRange\": [60, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Gel Series\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"R-Col.corr/L-Col.corr\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"R-Cal color/L-Cal.Filter\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"R-Storaro/L-600 Series\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"R-Cinelux/L-Cosmetic\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"R-Backup/L-700 Series\"\n        },\n        {\n          \"dmxRange\": [50, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Gel Model\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Gel Model selection (dependent on Gel R/L and Gel Series)\"\n      }\n    },\n    \"Source\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Generic\",\n          \"comment\": \"Tungsten Bulb\"\n        },\n        {\n          \"dmxRange\": [2, 3],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"Generic\",\n          \"comment\": \"Halogeen\"\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"Generic\",\n          \"comment\": \"Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Warm Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"Generic\",\n          \"comment\": \"Christmas lights\"\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"Generic\",\n          \"comment\": \"Night Light\"\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"Generic\",\n          \"comment\": \"Infrared Heat Lamp\"\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"Generic\",\n          \"comment\": \"Grow Light\"\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"CFL Soft White\"\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"Generic\",\n          \"comment\": \"CFL Bright White\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"Generic\",\n          \"comment\": \"CFL Cool White\"\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"Generic\",\n          \"comment\": \"CFL Daylight\"\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"Generic\",\n          \"comment\": \"Cool White 1\"\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Cool White 2\"\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"Generic\",\n          \"comment\": \"Cool White 3\"\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"Generic\",\n          \"comment\": \"Warm White\"\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"Generic\",\n          \"comment\": \"CFL BlackLight\"\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"Generic\",\n          \"comment\": \"HMI\"\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"High Presure Sodium\"\n        },\n        {\n          \"dmxRange\": [40, 41],\n          \"type\": \"Generic\",\n          \"comment\": \"Low Presure Sodium\"\n        },\n        {\n          \"dmxRange\": [42, 43],\n          \"type\": \"Generic\",\n          \"comment\": \"Mercury Vapor\"\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"Generic\",\n          \"comment\": \"Metal Halyde\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"Generic\",\n          \"comment\": \"Ceramic\"\n        },\n        {\n          \"dmxRange\": [48, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Carbon Arc\"\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"Generic\",\n          \"comment\": \"Xenon\"\n        },\n        {\n          \"dmxRange\": [52, 53],\n          \"type\": \"Generic\",\n          \"comment\": \"Candle\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"Generic\",\n          \"comment\": \"Gas Fire\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"Generic\",\n          \"comment\": \"Sun Direct\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"Sun Overcast\"\n        },\n        {\n          \"dmxRange\": [60, 61],\n          \"type\": \"Generic\",\n          \"comment\": \"Sun Blue Hour\"\n        },\n        {\n          \"dmxRange\": [62, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"Mobile Phone\"\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"Generic\",\n          \"comment\": \"Computer Monitor\"\n        },\n        {\n          \"dmxRange\": [66, 67],\n          \"type\": \"Generic\",\n          \"comment\": \"Electroluminescence\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"Generic\",\n          \"comment\": \"Blow Torch\"\n        },\n        {\n          \"dmxRange\": [70, 71],\n          \"type\": \"Generic\",\n          \"comment\": \"Road Flare\"\n        },\n        {\n          \"dmxRange\": [72, 73],\n          \"type\": \"Generic\",\n          \"comment\": \"Amber Caution\"\n        },\n        {\n          \"dmxRange\": [74, 75],\n          \"type\": \"Generic\",\n          \"comment\": \"Green Traffic Light\"\n        },\n        {\n          \"dmxRange\": [76, 77],\n          \"type\": \"Generic\",\n          \"comment\": \"Yellow Traffic Light\"\n        },\n        {\n          \"dmxRange\": [78, 79],\n          \"type\": \"Generic\",\n          \"comment\": \"Red Traffic Light\"\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"Generic\",\n          \"comment\": \"Blue Glow Stick\"\n        },\n        {\n          \"dmxRange\": [82, 83],\n          \"type\": \"Generic\",\n          \"comment\": \"Green Glow Stick\"\n        },\n        {\n          \"dmxRange\": [84, 85],\n          \"type\": \"Generic\",\n          \"comment\": \"Red Glow Stick\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"Generic\",\n          \"comment\": \"Yellow Glow Stick\"\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"Generic\",\n          \"comment\": \"Pink Glow Stick\"\n        },\n        {\n          \"dmxRange\": [90, 91],\n          \"type\": \"Generic\",\n          \"comment\": \"Violet Glow Stick\"\n        },\n        {\n          \"dmxRange\": [92, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Backup\"\n        }\n      ]\n    },\n    \"X\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0 … 0.8\"\n      }\n    },\n    \"Y\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0 … 0.8\"\n      }\n    },\n    \"Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Club Lights\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Paperazzi\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Candle\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Generic\",\n          \"comment\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Generic\",\n          \"comment\": \"Explosion\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Generic\",\n          \"comment\": \"Faulty Bulb\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Generic\",\n          \"comment\": \"Welding\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"Cop Car\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Generic\",\n          \"comment\": \"Color Chase\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Generic\",\n          \"comment\": \"Party Lights\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Backup\"\n        }\n      ]\n    },\n    \"Effect Parameter 1\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Dependent on Effect\"\n      }\n    },\n    \"Effect Parameter 2\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Dependent on Effect\"\n      }\n    },\n    \"Effect Parameter 3\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Dependent on Effect\"\n      }\n    },\n    \"Effect Parameter 4\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Dependent on Effect\"\n      }\n    },\n    \"Effect Parameter 5\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Dependent on Effect\"\n      }\n    },\n    \"Effect Parameter 6\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Dependent on Effect\"\n      }\n    },\n    \"Effect Parameter 7\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Dependent on Effect\"\n      }\n    },\n    \"Effect Parameter 8\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Dependent on Effect\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT&RGB\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Green/Magenta Point\",\n        \"CCT <-> RGB\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"CCT\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Green/Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"CCT&HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Green/Magenta Point\",\n        \"CCT <-> HSI\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"GEL\",\n      \"channels\": [\n        \"Intensity\",\n        \"Gel CCT\",\n        \"Gel R/L\",\n        \"Gel Series\",\n        \"Gel Model\"\n      ]\n    },\n    {\n      \"name\": \"HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"Source\",\n      \"channels\": [\n        \"Intensity\",\n        \"Source\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"X-Y\",\n      \"channels\": [\n        \"Intensity\",\n        \"X\",\n        \"Y\"\n      ]\n    },\n    {\n      \"name\": \"Effect\",\n      \"channels\": [\n        \"Effect\",\n        \"Intensity\",\n        \"Effect Parameter 1\",\n        \"Effect Parameter 2\",\n        \"Effect Parameter 3\",\n        \"Effect Parameter 4\",\n        \"Effect Parameter 5\",\n        \"Effect Parameter 6\",\n        \"Effect Parameter 7\",\n        \"Effect Parameter 8\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/arri/broadcaster-2-plus.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Broadcaster 2 Plus\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Giulio\"],\n    \"createDate\": \"2019-08-26\",\n    \"lastModifyDate\": \"2019-08-26\"\n  },\n  \"comment\": \"Controllable via 4-pin XLR PowerDMX.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.arri.com/resource/blob/31158/de6629cdb138a59ca92684f4e9b7fa59/arri-caster-user-manual-en-apr2015-l02583-data.pdf\",\n      \"https://www.arri.com/resource/blob/31096/bd7dfefbb42a8bc2d9a27857cba780f4/arri-caster-2-plus-datasheet-en-apr2014-data.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.arri.com/en/lighting/led/discontinued/caster-series/broadcaster-2-plus\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=uDUITNNHRQE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [218, 96, 70],\n    \"weight\": 0.96,\n    \"power\": 35,\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"name\": \"Prismatic Homogenizing Lense\",\n      \"degreesMinMax\": [63, 63]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"6500K\"\n      }\n    },\n    \"Plus/Minus Green\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Reserved\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Plus/Minus Green\",\n        \"Reserved\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/arri/l10-c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"L10-C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-09-21\",\n    \"lastModifyDate\": \"2020-09-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.arri.com/resource/blob/31168/649ca2ae2935bc75686e42fbe388e07f/l5-0006896-arri-l-series-l10-user-manual-en-nov2018-l03301-data.pdf\",\n      \"https://www.arri.com/resource/blob/65926/3b71e4fe69caea09f657fa8d599a55ab/l5-0022935-arri-l-series-dmx-protocol-specification-v3-4-data.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.arri.com/en/lighting/led-spotlights/discontinued/l-series-c/l10-c\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=6FEXDBjj9dw\",\n      \"https://www.youtube.com/watch?v=FFqDdU5SHOs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [428, 395, 745],\n    \"weight\": 19,\n    \"power\": 510,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 50]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Green-Magenta Point 8bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 16bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"fineChannelAliases\": [\"Green-Magenta Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5000],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [5001, 10000],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [10001, 29999],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [30000, 40000],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [40001, 59999],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [60000, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Cross Fade to Color\": {\n      \"fineChannelAliases\": [\"Cross Fade to Color fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"White … RGBW/HSI color\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P01: CCT & RGBW 8bit\",\n      \"shortName\": \"P01\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"P02: CCT 8bit\",\n      \"shortName\": \"P02\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"P03: CCT & HSI 8bit\",\n      \"shortName\": \"P03\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P04: RGBW 8bit\",\n      \"shortName\": \"P04\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"P05: HSI 8bit\",\n      \"shortName\": \"P05\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P06: CCT & RGBW 16bit\",\n      \"shortName\": \"P06\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P07: CCT 16bit\",\n      \"shortName\": \"P07\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"P08: CCT & HSI 16bit\",\n      \"shortName\": \"P08\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P09: RGBW 16bit\",\n      \"shortName\": \"P09\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P10: HSI 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P11: CCT & RGBW 8/16bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P12: CCT 8/16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"P13: CCT & HSI 8/16bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P14: RGBW 8/16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P15: HSI 8/16bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/arri/l5-c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"L5-C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-09-21\",\n    \"lastModifyDate\": \"2020-09-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.arri.com/resource/blob/31162/7aec274265c90d533cad5ae8b36ee85b/l5-0002357-arri-l-series-l5-user-manual-en-nov2018-l03301-data.pdf\",\n      \"https://www.arri.com/resource/blob/65926/3b71e4fe69caea09f657fa8d599a55ab/l5-0022935-arri-l-series-dmx-protocol-specification-v3-4-data.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.arri.com/en/lighting/led-spotlights/discontinued/l-series-c/l5-c\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=P5aUA5M-CXU\",\n      \"https://www.youtube.com/watch?v=FFqDdU5SHOs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [220, 240, 373],\n    \"weight\": 5.2,\n    \"power\": 115,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14, 50]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Green-Magenta Point 8bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 16bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"fineChannelAliases\": [\"Green-Magenta Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5000],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [5001, 10000],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [10001, 29999],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [30000, 40000],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [40001, 59999],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [60000, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Cross Fade to Color\": {\n      \"fineChannelAliases\": [\"Cross Fade to Color fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"White … RGBW/HSI color\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P01: CCT & RGBW 8bit\",\n      \"shortName\": \"P01\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"P02: CCT 8bit\",\n      \"shortName\": \"P02\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"P03: CCT & HSI 8bit\",\n      \"shortName\": \"P03\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P04: RGBW 8bit\",\n      \"shortName\": \"P04\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"P05: HSI 8bit\",\n      \"shortName\": \"P05\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P06: CCT & RGBW 16bit\",\n      \"shortName\": \"P06\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P07: CCT 16bit\",\n      \"shortName\": \"P07\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"P08: CCT & HSI 16bit\",\n      \"shortName\": \"P08\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P09: RGBW 16bit\",\n      \"shortName\": \"P09\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P10: HSI 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P11: CCT & RGBW 8/16bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P12: CCT 8/16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"P13: CCT & HSI 8/16bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P14: RGBW 8/16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P15: HSI 8/16bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/arri/l7-c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"L7-C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-09-21\",\n    \"lastModifyDate\": \"2020-09-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.arri.com/resource/blob/31174/a4c3f71a4eeba9381897ffee38676993/l5-31899-0-arri-l-series-l7-user-manual-en-nov2018-l03301-data.pdf\",\n      \"https://www.arri.com/resource/blob/65926/3b71e4fe69caea09f657fa8d599a55ab/l5-0022935-arri-l-series-dmx-protocol-specification-v3-4-data.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.arri.com/en/lighting/led-spotlights/discontinued/l-series-c/l7-c\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=RbUNbA0HPls\",\n      \"https://www.youtube.com/watch?v=FFqDdU5SHOs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [300, 308, 456],\n    \"weight\": 8.2,\n    \"power\": 220,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 50]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Green-Magenta Point 8bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 16bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"fineChannelAliases\": [\"Green-Magenta Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5000],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [5001, 10000],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [10001, 29999],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [30000, 40000],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [40001, 59999],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [60000, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Cross Fade to Color\": {\n      \"fineChannelAliases\": [\"Cross Fade to Color fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"White … RGBW/HSI color\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P01: CCT & RGBW 8bit\",\n      \"shortName\": \"P01\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"P02: CCT 8bit\",\n      \"shortName\": \"P02\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"P03: CCT & HSI 8bit\",\n      \"shortName\": \"P03\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P04: RGBW 8bit\",\n      \"shortName\": \"P04\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"P05: HSI 8bit\",\n      \"shortName\": \"P05\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P06: CCT & RGBW 16bit\",\n      \"shortName\": \"P06\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P07: CCT 16bit\",\n      \"shortName\": \"P07\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"P08: CCT & HSI 16bit\",\n      \"shortName\": \"P08\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P09: RGBW 16bit\",\n      \"shortName\": \"P09\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P10: HSI 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P11: CCT & RGBW 8/16bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P12: CCT 8/16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"P13: CCT & HSI 8/16bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P14: RGBW 8/16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"P15: HSI 8/16bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/arri/skypanel-s120c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Skypanel S120C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jean-François Losson\", \"Dyami Caliri\"],\n    \"createDate\": \"2020-10-02\",\n    \"lastModifyDate\": \"2020-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.arri.com/resource/blob/31208/e3a435411261f80aee556508014ce2dd/arri-skypanel-user-manual-en-nov2018-l03301-data.pdf\",\n      \"https://www.arri.com/resource/blob/65958/560471fec7f8f2e186ef8ca9e6cdd489/arri-skypanel-dmx-protocol-specification-v4-4-en-okt2018-data.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.arri.com/en/lighting/led-panel-lights/skypanel-classic/s120-c\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Qq9xhKwpZqc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1332, 347, 133],\n    \"weight\": 13.7,\n    \"power\": 400,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [110, 110]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Green-Magenta Point 8bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 16bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"fineChannelAliases\": [\"Green-Magenta Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4587],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [4588, 9830],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [9831, 30146],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [30147, 39976],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [39977, 60292],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [60293, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Cross Fade to Color\": {\n      \"fineChannelAliases\": [\"Cross Fade to Color fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"White … RGBW/HSI color\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Fan Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use Fan Mode of Fixture Menu\"\n        },\n        {\n          \"dmxRange\": [10, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Quiet, Fan speed fixed\"\n        },\n        {\n          \"dmxRange\": [58, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Variable, Fan speed variable\"\n        },\n        {\n          \"dmxRange\": [106, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"High Temp, Fan speed fixed\"\n        },\n        {\n          \"dmxRange\": [154, 201],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [202, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan At Full Speed\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Is this capability really here? Or is it just a typo in the manual?\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan off\"\n        }\n      ]\n    },\n    \"Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 01 - User Defined\"\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 02 - User Defined\"\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 03 - User Defined\"\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 04 - User Defined\"\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 05 - User Defined\"\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 06 - User Defined\"\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 07 - User Defined\"\n        },\n        {\n          \"dmxRange\": [96, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 08 - User Defined\"\n        },\n        {\n          \"dmxRange\": [108, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 09 - User Defined\"\n        },\n        {\n          \"dmxRange\": [120, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10 - User Defined\"\n        },\n        {\n          \"dmxRange\": [132, 143],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"2900K\",\n          \"comment\": \"Preset 01\"\n        },\n        {\n          \"dmxRange\": [144, 155],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"Preset 02\"\n        },\n        {\n          \"dmxRange\": [156, 167],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"5600K\",\n          \"comment\": \"Preset 03\"\n        },\n        {\n          \"dmxRange\": [168, 179],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"6500K\",\n          \"comment\": \"Preset 04\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 05 - 120° Hue, 100% Saturation\"\n        },\n        {\n          \"dmxRange\": [192, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 06 - 240° Hue, 100% Saturation\"\n        },\n        {\n          \"dmxRange\": [204, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 07 - Rosco 3408\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [216, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 08 - Lee 187\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [228, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 09 - Rosco 3152\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10 - Lee 162\",\n          \"colorTemperature\": \"3200K\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Reserved for future use\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P01: CCT & RGBW 8bit\",\n      \"shortName\": \"P01\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P02: CCT 8bit\",\n      \"shortName\": \"P02\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P03: CCT & HSI 8bit\",\n      \"shortName\": \"P03\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P04: RGBW 8bit\",\n      \"shortName\": \"P04\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P05: HSI 8bit\",\n      \"shortName\": \"P05\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P06: CCT & RGBW 16bit\",\n      \"shortName\": \"P06\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P07: CCT 16bit\",\n      \"shortName\": \"P07\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P08: CCT & HSI 16bit\",\n      \"shortName\": \"P08\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P09: RGBW 16bit\",\n      \"shortName\": \"P09\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P10: HSI 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P11: CCT & RGBW 8/16bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P12: CCT 8/16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P13: CCT & HSI 8/16bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P14: RGBW 8/16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P15: HSI 8/16bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/arri/skypanel-s30c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Skypanel S30C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jean-François Losson\", \"JonahKr\"],\n    \"createDate\": \"2018-10-17\",\n    \"lastModifyDate\": \"2021-09-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.arri.com/resource/blob/31208/e3a435411261f80aee556508014ce2dd/arri-skypanel-user-manual-en-nov2018-l03301-data.pdf\",\n      \"https://www.arri.com/resource/blob/65958/560471fec7f8f2e186ef8ca9e6cdd489/arri-skypanel-dmx-protocol-specification-v4-4-en-okt2018-data.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.arri.com/en/lighting/led-panel-lights/skypanel-classic/s30-c\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Qq9xhKwpZqc\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 514,\n    \"softwareVersion\": \"4.1\"\n  },\n  \"physical\": {\n    \"dimensions\": [499, 133, 397],\n    \"weight\": 8,\n    \"power\": 220,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [115, 115]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Green-Magenta Point 8bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 16bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"fineChannelAliases\": [\"Green-Magenta Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4587],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [4588, 9830],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [9831, 30146],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [30147, 39976],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [39977, 60292],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [60293, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Cross Fade to Color\": {\n      \"fineChannelAliases\": [\"Cross Fade to Color fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"White … RGBW/HSI color\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Fan Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use Fan Mode of Fixture Menu\"\n        },\n        {\n          \"dmxRange\": [10, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Quiet, Fan speed fixed\"\n        },\n        {\n          \"dmxRange\": [58, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Variable, Fan speed variable\"\n        },\n        {\n          \"dmxRange\": [106, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"High Temp, Fan speed fixed\"\n        },\n        {\n          \"dmxRange\": [154, 201],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [202, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan At Full Speed\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Is this capability really here? Or is it just a typo in the manual?\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan off\"\n        }\n      ]\n    },\n    \"Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 01 - User Defined\"\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 02 - User Defined\"\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 03 - User Defined\"\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 04 - User Defined\"\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 05 - User Defined\"\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 06 - User Defined\"\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 07 - User Defined\"\n        },\n        {\n          \"dmxRange\": [96, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 08 - User Defined\"\n        },\n        {\n          \"dmxRange\": [108, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 09 - User Defined\"\n        },\n        {\n          \"dmxRange\": [120, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10 - User Defined\"\n        },\n        {\n          \"dmxRange\": [132, 143],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"2900K\",\n          \"comment\": \"Preset 01\",\n          \"colors\": [\"#ffb165\"]\n        },\n        {\n          \"dmxRange\": [144, 155],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"Preset 02\",\n          \"colors\": [\"#ffbb78\"]\n        },\n        {\n          \"dmxRange\": [156, 167],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"5600K\",\n          \"comment\": \"Preset 03\",\n          \"colors\": [\"#ffe8d5\"]\n        },\n        {\n          \"dmxRange\": [168, 179],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"6500K\",\n          \"comment\": \"Preset 04\",\n          \"colors\": [\"#fff9fd\"]\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 05 - 120° Hue, 100% Saturation\"\n        },\n        {\n          \"dmxRange\": [192, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 06 - 240° Hue, 100% Saturation\"\n        },\n        {\n          \"dmxRange\": [204, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 07 - Rosco 3408\",\n          \"colorTemperature\": \"5600K\",\n          \"colors\": [\"#fcc286\"]\n        },\n        {\n          \"dmxRange\": [216, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 08 - Lee 187\",\n          \"colorTemperature\": \"3200K\",\n          \"colors\": [\"#f5e4d7\"]\n        },\n        {\n          \"dmxRange\": [228, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 09 - Rosco 3152\",\n          \"colorTemperature\": \"3200K\",\n          \"colors\": [\"#f5802c\"]\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10 - Lee 162\",\n          \"colorTemperature\": \"3200K\",\n          \"colors\": [\"#fcded8\"]\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Reserved for future use\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P01: CCT & RGBW 8bit\",\n      \"shortName\": \"P01\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P02: CCT 8bit\",\n      \"shortName\": \"P02\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P03: CCT & HSI 8bit\",\n      \"shortName\": \"P03\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P04: RGBW 8bit\",\n      \"shortName\": \"P04\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P05: HSI 8bit\",\n      \"shortName\": \"P05\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P06: CCT & RGBW 16bit\",\n      \"shortName\": \"P06\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P07: CCT 16bit\",\n      \"shortName\": \"P07\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P08: CCT & HSI 16bit\",\n      \"shortName\": \"P08\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P09: RGBW 16bit\",\n      \"shortName\": \"P09\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P10: HSI 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P11: CCT & RGBW 8/16bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P12: CCT 8/16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P13: CCT & HSI 8/16bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P14: RGBW 8/16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P15: HSI 8/16bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/arri/skypanel-s360c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Skypanel S360C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jean-François Losson\", \"Dyami Caliri\"],\n    \"createDate\": \"2020-10-02\",\n    \"lastModifyDate\": \"2020-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.arri.com/resource/blob/31208/e3a435411261f80aee556508014ce2dd/arri-skypanel-user-manual-en-nov2018-l03301-data.pdf\",\n      \"https://www.arri.com/resource/blob/65958/560471fec7f8f2e186ef8ca9e6cdd489/arri-skypanel-dmx-protocol-specification-v4-4-en-okt2018-data.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.arri.com/en/lighting/led-panel-lights/skypanel-classic/s360-c\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=0S35iTuTxBo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1331, 947, 186],\n    \"weight\": 41,\n    \"power\": 1500,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [105, 105]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Green-Magenta Point 8bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 16bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"fineChannelAliases\": [\"Green-Magenta Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4587],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [4588, 9830],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [9831, 30146],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [30147, 39976],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [39977, 60292],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [60293, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Cross Fade to Color\": {\n      \"fineChannelAliases\": [\"Cross Fade to Color fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"White … RGBW/HSI color\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Fan Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use Fan Mode of Fixture Menu\"\n        },\n        {\n          \"dmxRange\": [10, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Quiet, Fan speed fixed\"\n        },\n        {\n          \"dmxRange\": [58, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Variable, Fan speed variable\"\n        },\n        {\n          \"dmxRange\": [106, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"High Temp, Fan speed fixed\"\n        },\n        {\n          \"dmxRange\": [154, 201],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [202, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan At Full Speed\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Is this capability really here? Or is it just a typo in the manual?\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan off\"\n        }\n      ]\n    },\n    \"Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 01 - User Defined\"\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 02 - User Defined\"\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 03 - User Defined\"\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 04 - User Defined\"\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 05 - User Defined\"\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 06 - User Defined\"\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 07 - User Defined\"\n        },\n        {\n          \"dmxRange\": [96, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 08 - User Defined\"\n        },\n        {\n          \"dmxRange\": [108, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 09 - User Defined\"\n        },\n        {\n          \"dmxRange\": [120, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10 - User Defined\"\n        },\n        {\n          \"dmxRange\": [132, 143],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"2900K\",\n          \"comment\": \"Preset 01\"\n        },\n        {\n          \"dmxRange\": [144, 155],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"Preset 02\"\n        },\n        {\n          \"dmxRange\": [156, 167],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"5600K\",\n          \"comment\": \"Preset 03\"\n        },\n        {\n          \"dmxRange\": [168, 179],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"6500K\",\n          \"comment\": \"Preset 04\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 05 - 120° Hue, 100% Saturation\"\n        },\n        {\n          \"dmxRange\": [192, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 06 - 240° Hue, 100% Saturation\"\n        },\n        {\n          \"dmxRange\": [204, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 07 - Rosco 3408\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [216, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 08 - Lee 187\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [228, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 09 - Rosco 3152\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10 - Lee 162\",\n          \"colorTemperature\": \"3200K\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Reserved for future use\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P01: CCT & RGBW 8bit\",\n      \"shortName\": \"P01\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P02: CCT 8bit\",\n      \"shortName\": \"P02\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P03: CCT & HSI 8bit\",\n      \"shortName\": \"P03\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P04: RGBW 8bit\",\n      \"shortName\": \"P04\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P05: HSI 8bit\",\n      \"shortName\": \"P05\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P06: CCT & RGBW 16bit\",\n      \"shortName\": \"P06\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P07: CCT 16bit\",\n      \"shortName\": \"P07\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P08: CCT & HSI 16bit\",\n      \"shortName\": \"P08\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P09: RGBW 16bit\",\n      \"shortName\": \"P09\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P10: HSI 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P11: CCT & RGBW 8/16bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P12: CCT 8/16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P13: CCT & HSI 8/16bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P14: RGBW 8/16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P15: HSI 8/16bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/arri/skypanel-s60c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Skypanel S60C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jean-François Losson\", \"Dyami Caliri\"],\n    \"createDate\": \"2020-10-02\",\n    \"lastModifyDate\": \"2020-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.arri.com/resource/blob/31208/e3a435411261f80aee556508014ce2dd/arri-skypanel-user-manual-en-nov2018-l03301-data.pdf\",\n      \"https://www.arri.com/resource/blob/65958/560471fec7f8f2e186ef8ca9e6cdd489/arri-skypanel-dmx-protocol-specification-v4-4-en-okt2018-data.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.arri.com/en/lighting/led-spotlights/discontinued/s60-c\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=dXyYn9xfGXY\",\n      \"https://www.youtube.com/watch?v=2xrOoLjaFfU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [688, 347, 133],\n    \"weight\": 12.8,\n    \"power\": 420,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [115, 115]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Green-Magenta Point 8bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 16bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"fineChannelAliases\": [\"Green-Magenta Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4587],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [4588, 9830],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [9831, 30146],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [30147, 39976],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [39977, 60292],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [60293, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Cross Fade to Color\": {\n      \"fineChannelAliases\": [\"Cross Fade to Color fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"White … RGBW/HSI color\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Fan Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use Fan Mode of Fixture Menu\"\n        },\n        {\n          \"dmxRange\": [10, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Quiet, Fan speed fixed\"\n        },\n        {\n          \"dmxRange\": [58, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Variable, Fan speed variable\"\n        },\n        {\n          \"dmxRange\": [106, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"High Temp, Fan speed fixed\"\n        },\n        {\n          \"dmxRange\": [154, 201],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [202, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan At Full Speed\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Is this capability really here? Or is it just a typo in the manual?\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan off\"\n        }\n      ]\n    },\n    \"Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 01 - User Defined\"\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 02 - User Defined\"\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 03 - User Defined\"\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 04 - User Defined\"\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 05 - User Defined\"\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 06 - User Defined\"\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 07 - User Defined\"\n        },\n        {\n          \"dmxRange\": [96, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 08 - User Defined\"\n        },\n        {\n          \"dmxRange\": [108, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 09 - User Defined\"\n        },\n        {\n          \"dmxRange\": [120, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10 - User Defined\"\n        },\n        {\n          \"dmxRange\": [132, 143],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"2900K\",\n          \"comment\": \"Preset 01\"\n        },\n        {\n          \"dmxRange\": [144, 155],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"Preset 02\"\n        },\n        {\n          \"dmxRange\": [156, 167],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"5600K\",\n          \"comment\": \"Preset 03\"\n        },\n        {\n          \"dmxRange\": [168, 179],\n          \"type\": \"ColorPreset\",\n          \"colorTemperature\": \"6500K\",\n          \"comment\": \"Preset 04\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 05 - 120° Hue, 100% Saturation\"\n        },\n        {\n          \"dmxRange\": [192, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 06 - 240° Hue, 100% Saturation\"\n        },\n        {\n          \"dmxRange\": [204, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 07 - Rosco 3408\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [216, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 08 - Lee 187\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [228, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 09 - Rosco 3152\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10 - Lee 162\",\n          \"colorTemperature\": \"3200K\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Reserved for future use\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P01: CCT & RGBW 8bit\",\n      \"shortName\": \"P01\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P02: CCT 8bit\",\n      \"shortName\": \"P02\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P03: CCT & HSI 8bit\",\n      \"shortName\": \"P03\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P04: RGBW 8bit\",\n      \"shortName\": \"P04\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P05: HSI 8bit\",\n      \"shortName\": \"P05\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P06: CCT & RGBW 16bit\",\n      \"shortName\": \"P06\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P07: CCT 16bit\",\n      \"shortName\": \"P07\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P08: CCT & HSI 16bit\",\n      \"shortName\": \"P08\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Cross Fade to Color\",\n        \"Cross Fade to Color fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P09: RGBW 16bit\",\n      \"shortName\": \"P09\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P10: HSI 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P11: CCT & RGBW 8/16bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P12: CCT 8/16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P13: CCT & HSI 8/16bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 8bit\",\n        \"Cross Fade to Color\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P14: RGBW 8/16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"P15: HSI 8/16bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan Control\",\n        \"Presets\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/astera/ax3-lightdrop.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"AX3 Lightdrop\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Fredje Gallon\", \"Anomes\"],\n    \"createDate\": \"2020-03-29\",\n    \"lastModifyDate\": \"2020-03-29\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2020-03-29\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.3 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.astera-led.com/Downloads/manual/AX3%20Manual%20%28EN%29.pdf\"\n    ],\n    \"productPage\": [\n      \"https://astera-led.com/products/ax3-lightdrop/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=1QZb19aNqAg\",\n      \"https://www.youtube.com/watch?v=u9XPp9icNiA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [96.4, 96.4, 59],\n    \"weight\": 0.4,\n    \"power\": 15,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 4000,\n      \"lumens\": 420\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Master dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature CCT\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"default\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2100K\",\n          \"colorTemperatureEnd\": \"7100K\",\n          \"comment\": \"Color Temperature = 2000 + 20*DMX-Value\"\n        }\n      ]\n    },\n    \"LEE Color Gel 1\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No effect\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\"\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\"\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\"\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\"\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\"\n        },\n        {\n          \"dmxRange\": [29, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Plasa Red\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\"\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\"\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Purple\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\"\n        },\n        {\n          \"dmxRange\": [53, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\"\n        },\n        {\n          \"dmxRange\": [58, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\"\n        },\n        {\n          \"dmxRange\": [63, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\"\n        },\n        {\n          \"dmxRange\": [68, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\"\n        },\n        {\n          \"dmxRange\": [71, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tokyo Blue\"\n        },\n        {\n          \"dmxRange\": [75, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Evening Blue\"\n        },\n        {\n          \"dmxRange\": [79, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\"\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Yellow Green\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\"\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\"\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\"\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\"\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\"\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\"\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue-Green\"\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\"\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\"\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\"\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Green\"\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Heavy Frost\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Clear\"\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\"\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Golden Amber\"\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\"\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\"\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\"\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\"\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\"\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\"\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Blue\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\"\n        },\n        {\n          \"dmxRange\": [148, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\"\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\"\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\"\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\"\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Straw\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\"\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\"\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\"\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\"\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\"\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\"\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\"\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Rose\"\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Rouge\"\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Highlight\"\n        },\n        {\n          \"dmxRange\": [189, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Moss\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Aqua Blue\"\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\"\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\"\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\"\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\"\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\"\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Regal Blue\"\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CT Blue\"\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Blue\"\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Blue\"\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Blue\"\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange\"\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Orange\"\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Orange\"\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\"\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\"\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.3 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.6 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.9 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LCT Yellow\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Flame Green\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Diffusion\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Diffusion\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Blue\"\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent Green\"\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Frost\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Frost\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Orange\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue Frost\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE N.D. Frost\"\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE U.V.\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brushed Silk\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Tough Spun\"\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Correction\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super White Flame Green\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"H.M.I (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.I.D. (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.S.I. (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [239, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Polariser\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 5700 K\"\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 4300 K\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 3600 K\"\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Plus Green\"\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Plus Green\"\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Plus Green\"\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Minus Green\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Minus Green\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Minus Green\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hampshire Frost\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"New Hampshire Frost\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Frost\"\n        }\n      ]\n    },\n    \"LEE Color Gel 2\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No effect\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\"\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\"\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\"\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\"\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\"\n        },\n        {\n          \"dmxRange\": [29, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Plasa Red\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\"\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\"\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Purple\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\"\n        },\n        {\n          \"dmxRange\": [53, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\"\n        },\n        {\n          \"dmxRange\": [58, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\"\n        },\n        {\n          \"dmxRange\": [63, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\"\n        },\n        {\n          \"dmxRange\": [68, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\"\n        },\n        {\n          \"dmxRange\": [71, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tokyo Blue\"\n        },\n        {\n          \"dmxRange\": [75, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Evening Blue\"\n        },\n        {\n          \"dmxRange\": [79, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\"\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Yellow Green\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\"\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\"\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\"\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\"\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\"\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\"\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue-Green\"\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\"\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\"\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\"\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Green\"\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Heavy Frost\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Clear\"\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\"\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Golden Amber\"\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\"\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\"\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\"\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\"\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\"\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\"\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Blue\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\"\n        },\n        {\n          \"dmxRange\": [148, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\"\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\"\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\"\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\"\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Straw\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\"\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\"\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\"\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\"\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\"\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\"\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\"\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Rose\"\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Rouge\"\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Highlight\"\n        },\n        {\n          \"dmxRange\": [189, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Moss\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Aqua Blue\"\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\"\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\"\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\"\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\"\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\"\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Regal Blue\"\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CT Blue\"\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Blue\"\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Blue\"\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Blue\"\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange\"\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Orange\"\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Orange\"\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\"\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\"\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.3 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.6 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.9 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LCT Yellow\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Flame Green\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Diffusion\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Diffusion\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Blue\"\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent Green\"\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Frost\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Frost\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Orange\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue Frost\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE N.D. Frost\"\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE U.V.\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brushed Silk\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Tough Spun\"\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Correction\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super White Flame Green\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"H.M.I (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.I.D. (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.S.I. (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [239, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Polariser\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 5700 K\"\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 4300 K\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 3600 K\"\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Plus Green\"\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Plus Green\"\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Plus Green\"\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Minus Green\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Minus Green\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Minus Green\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hampshire Frost\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"New Hampshire Frost\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Frost\"\n        }\n      ]\n    },\n    \"LEE Color Gel 3\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No effect\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\"\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\"\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\"\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\"\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\"\n        },\n        {\n          \"dmxRange\": [29, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Plasa Red\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\"\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\"\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Purple\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\"\n        },\n        {\n          \"dmxRange\": [53, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\"\n        },\n        {\n          \"dmxRange\": [58, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\"\n        },\n        {\n          \"dmxRange\": [63, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\"\n        },\n        {\n          \"dmxRange\": [68, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\"\n        },\n        {\n          \"dmxRange\": [71, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tokyo Blue\"\n        },\n        {\n          \"dmxRange\": [75, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Evening Blue\"\n        },\n        {\n          \"dmxRange\": [79, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\"\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Yellow Green\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\"\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\"\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\"\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\"\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\"\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\"\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue-Green\"\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\"\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\"\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\"\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Green\"\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Heavy Frost\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Clear\"\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\"\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Golden Amber\"\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\"\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\"\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\"\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\"\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\"\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\"\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Blue\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\"\n        },\n        {\n          \"dmxRange\": [148, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\"\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\"\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\"\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\"\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Straw\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\"\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\"\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\"\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\"\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\"\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\"\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\"\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Rose\"\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Rouge\"\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Highlight\"\n        },\n        {\n          \"dmxRange\": [189, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Moss\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Aqua Blue\"\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\"\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\"\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\"\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\"\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\"\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Regal Blue\"\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CT Blue\"\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Blue\"\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Blue\"\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Blue\"\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange\"\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Orange\"\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Orange\"\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\"\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\"\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.3 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.6 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.9 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LCT Yellow\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Flame Green\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Diffusion\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Diffusion\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Blue\"\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent Green\"\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Frost\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Frost\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Orange\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue Frost\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE N.D. Frost\"\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE U.V.\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brushed Silk\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Tough Spun\"\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Correction\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super White Flame Green\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"H.M.I (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.I.D. (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.S.I. (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [239, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Polariser\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 5700 K\"\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 4300 K\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 3600 K\"\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Plus Green\"\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Plus Green\"\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Plus Green\"\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Minus Green\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Minus Green\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Minus Green\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hampshire Frost\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"New Hampshire Frost\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Frost\"\n        }\n      ]\n    },\n    \"LEE Color Gel 4\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No effect\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\"\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\"\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\"\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\"\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\"\n        },\n        {\n          \"dmxRange\": [29, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Plasa Red\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\"\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\"\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Purple\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\"\n        },\n        {\n          \"dmxRange\": [53, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\"\n        },\n        {\n          \"dmxRange\": [58, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\"\n        },\n        {\n          \"dmxRange\": [63, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\"\n        },\n        {\n          \"dmxRange\": [68, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\"\n        },\n        {\n          \"dmxRange\": [71, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tokyo Blue\"\n        },\n        {\n          \"dmxRange\": [75, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Evening Blue\"\n        },\n        {\n          \"dmxRange\": [79, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\"\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Yellow Green\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\"\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\"\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\"\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\"\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\"\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\"\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue-Green\"\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\"\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\"\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\"\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Green\"\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Heavy Frost\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Clear\"\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\"\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Golden Amber\"\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\"\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\"\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\"\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\"\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\"\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\"\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Blue\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\"\n        },\n        {\n          \"dmxRange\": [148, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\"\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\"\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\"\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\"\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Straw\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\"\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\"\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\"\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\"\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\"\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\"\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\"\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Rose\"\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Rouge\"\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Highlight\"\n        },\n        {\n          \"dmxRange\": [189, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Moss\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Aqua Blue\"\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\"\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\"\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\"\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\"\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\"\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Regal Blue\"\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CT Blue\"\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Blue\"\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Blue\"\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Blue\"\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange\"\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Orange\"\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Orange\"\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\"\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\"\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.3 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.6 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.9 Neutral Density\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LCT Yellow\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Flame Green\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Diffusion\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Diffusion\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Blue\"\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent Green\"\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Frost\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Frost\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Orange\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue Frost\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE N.D. Frost\"\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE U.V.\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brushed Silk\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Tough Spun\"\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Correction\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super White Flame Green\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"H.M.I (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.I.D. (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.S.I. (To Tungsten)\"\n        },\n        {\n          \"dmxRange\": [239, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Polariser\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 5700 K\"\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 4300 K\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 3600 K\"\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Plus Green\"\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Plus Green\"\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Plus Green\"\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Minus Green\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Minus Green\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Minus Green\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 White Diffusion\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hampshire Frost\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"New Hampshire Frost\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Frost\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"50%\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [7, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.4Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Static\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Static\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Static\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Static\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Fade\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Fade\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Fade\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Fade\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Simple Running\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Running\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Col Running\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flag Running\"\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Flag Running\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 4 Color\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 2 Color\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow\"\n        },\n        {\n          \"dmxRange\": [126, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [134, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor\"\n        },\n        {\n          \"dmxRange\": [142, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 2\"\n        },\n        {\n          \"dmxRange\": [150, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 4\"\n        },\n        {\n          \"dmxRange\": [158, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Cross Fade\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"Program Direction\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Forward with loop\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Forward one time and stop\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reverse one time and stop\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reverse with loop\"\n        }\n      ]\n    },\n    \"Program Group Size\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 1\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 2\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 3\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 4\n        }\n      ]\n    },\n    \"Program user Offset in Groups\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"off\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"with groups >1, the offset within the virtual large program\"\n      }\n    },\n    \"Program Restart\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\",\n        \"comment\": \"Change value to restart program\"\n      }\n    },\n    \"Intensity Red of Color 1\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Intensity Green of Color 1\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Intensity Blue of Color 1\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Intensity Red of Color 2\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Intensity Green of Color 2\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Intensity Blue of Color 2\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Intensity Red of Color 3\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Intensity Green of Color 3\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Intensity Blue of Color 3\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Intensity Red of Color 4\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Intensity Green of Color 4\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Intensity Blue of Color 4\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: RGB\",\n      \"shortName\": \"1-rgb\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"2: RGBW\",\n      \"shortName\": \"2-rgbw\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"3: RGBAW\",\n      \"shortName\": \"3-rgbaw\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        null,\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"4: DIM RGB\",\n      \"shortName\": \"4-dim-rgb\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"5: DIM RGBW\",\n      \"shortName\": \"5-dim-rgbw\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6: DIM RGBAW\",\n      \"shortName\": \"6-dim-rgbaw\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        null,\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"7: DIM RGB CCT DIM IND\",\n      \"shortName\": \"7-dim-rgb-cct-dim-ind\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Temperature CCT\",\n        \"Master dimmer\",\n        \"LEE Color Gel 1\"\n      ]\n    },\n    {\n      \"name\": \"8: RGBS\",\n      \"shortName\": \"8-rgbs\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"9: RGBWS\",\n      \"shortName\": \"9-rgbws\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"10: RGBAWS\",\n      \"shortName\": \"10-rgbaws\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        null,\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11: DIM RGBS\",\n      \"shortName\": \"11-dim-rgbs\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12: DIM RGBWS\",\n      \"shortName\": \"12-dim-rgbws\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"13: DIM RGBAWS\",\n      \"shortName\": \"13-dim-rgbaws\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        null,\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"14: RGB CCT DIM IND S\",\n      \"shortName\": \"14-rgb-cct-dim-ind-s\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Temperature CCT\",\n        \"Master dimmer\",\n        \"LEE Color Gel 1\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"15: EFFECT FIX\",\n      \"shortName\": \"15-effect-fix\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Strobe\",\n        \"Program\",\n        \"Program Speed\",\n        \"Program Cross Fade\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Program user Offset in Groups\",\n        \"Program Restart\",\n        \"LEE Color Gel 1\",\n        \"LEE Color Gel 2\",\n        \"LEE Color Gel 3\",\n        \"LEE Color Gel 4\"\n      ]\n    },\n    {\n      \"name\": \"16: EFFECT RGB\",\n      \"shortName\": \"16-effect-rgb\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Strobe\",\n        \"Program\",\n        \"Program Speed\",\n        \"Program Cross Fade\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Program user Offset in Groups\",\n        \"Program Restart\",\n        \"Intensity Red of Color 1\",\n        \"Intensity Green of Color 1\",\n        \"Intensity Blue of Color 1\",\n        \"Intensity Red of Color 2\",\n        \"Intensity Green of Color 2\",\n        \"Intensity Blue of Color 2\",\n        \"Intensity Red of Color 3\",\n        \"Intensity Green of Color 3\",\n        \"Intensity Blue of Color 3\",\n        \"Intensity Red of Color 4\",\n        \"Intensity Green of Color 4\",\n        \"Intensity Blue of Color 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/astera/fp1-titan-tube.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"FP1 Titan Tube\",\n  \"shortName\": \"AsteraFP1Titan\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\", \"Blinder\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jack Crombie\", \"Felix Edelmann\", \"Dyami Caliri\"],\n    \"createDate\": \"2019-07-09\",\n    \"lastModifyDate\": \"2021-01-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://astera-led.com/Downloads/manual/FP1_TitanTube_Manual.pdf\",\n      \"https://astera-led.com/Downloads/Profile/Titan%20Tube%20DMX%20Profiles.pdf\"\n    ],\n    \"productPage\": [\n      \"https://astera-led.com/products/titan/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=V83BQca2MDY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1035, 42, 42],\n    \"weight\": 1.35,\n    \"power\": 48,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 2900\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [64, 42, 42],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [16, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/4\": { \"x\": [\"<=4\"] },\n      \"2/4\": { \"x\": [\">=5\", \"<=8\"] },\n      \"3/4\": { \"x\": [\">=9\", \"<=12\"] },\n      \"4/4\": { \"x\": [\">=13\"] },\n      \"Effect Color 1\": \"all\",\n      \"Effect Color 2\": \"all\",\n      \"Effect Color 3\": \"all\",\n      \"Effect Color 4\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"fineChannelAliases\": [\"Dimmer $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Emulated White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2100K\",\n          \"colorTemperatureEnd\": \"7100K\",\n          \"helpWanted\": \"Does this capability already begin at DMX value 4 (with 2080K)?\"\n        }\n      ]\n    },\n    \"CCT $pixelKey\": {\n      \"capability\":\n        {\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1750K\",\n          \"colorTemperatureEnd\": \"9910K\"\n        }\n    },\n    \"Crossfade $pixelKey\": {\n      \"capability\":\n        {\n          \"type\": \"Generic\",\n          \"comment\": \"CCT crossfade to RGB\"\n        }\n    },\n    \"Green-Magenta Point $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…100%\"\n        }\n      ]\n    },\n    \"Hue $pixelKey\": {\n      \"fineChannelAliases\": [\"Hue $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"LEE Color Gel $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\",\n          \"colors\": [\"#ff8fb9\"]\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\",\n          \"colors\": [\"#ffdab5\"]\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Bastard Amber\",\n          \"colors\": [\"#ffb783\"]\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\",\n          \"colors\": [\"#ffd78c\"]\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\",\n          \"colors\": [\"#ff814c\"]\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\",\n          \"colors\": [\"#ffc176\"]\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\",\n          \"colors\": [\"#ffd21c\"]\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\",\n          \"colors\": [\"#ffc069\"]\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\",\n          \"colors\": [\"#ff9f00\"]\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\",\n          \"colors\": [\"#ffa25b\"]\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\",\n          \"colors\": [\"#ff391b\"]\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\",\n          \"colors\": [\"#ff9123\"]\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\",\n          \"colors\": [\"#ff7600\"]\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\",\n          \"colors\": [\"#ff4f0a\"]\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\",\n          \"colors\": [\"#ff5647\"]\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\",\n          \"colors\": [\"#ff6f2f\"]\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\",\n          \"colors\": [\"#ff0012\"]\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\",\n          \"colors\": [\"#ff0020\"]\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Plasa Red\",\n          \"colors\": [\"#ff2707\"]\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#ffbaa1\"]\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\",\n          \"colors\": [\"#ff9f98\"]\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\",\n          \"colors\": [\"#ff0055\"]\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\",\n          \"colors\": [\"#ff95e0\"]\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Purple\",\n          \"colors\": [\"#ff50f1\"]\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\",\n          \"colors\": [\"#ffdcf6\"]\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\",\n          \"colors\": [\"#ffe5ca\"]\n        },\n        {\n          \"dmxRange\": [54, 57],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#af7cff\"]\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\",\n          \"colors\": [\"#fff9db\"]\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\",\n          \"colors\": [\"#f6ffeb\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#00acff\"]\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tokyo Blue\",\n          \"colors\": [\"#0040ff\"]\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Evening Blue\",\n          \"colors\": [\"#00a1ff\"]\n        },\n        {\n          \"dmxRange\": [76, 78],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\",\n          \"colors\": [\"#007bff\"]\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\",\n          \"colors\": [\"#0075ff\"]\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\",\n          \"colors\": [\"#fffe4c\"]\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\",\n          \"colors\": [\"#a7ff58\"]\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Yellow Green\",\n          \"colors\": [\"#3aff42\"]\n        },\n        {\n          \"dmxRange\": [91, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\",\n          \"colors\": [\"#ffd930\"]\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffc600\"]\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\",\n          \"colors\": [\"#ffba45\"]\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\",\n          \"colors\": [\"#ffd88f\"]\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\",\n          \"colors\": [\"#ffa704\"]\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8700\"]\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\",\n          \"colors\": [\"#ff0018\"]\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\",\n          \"colors\": [\"#ff8d7e\"]\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\",\n          \"colors\": [\"#ffa76b\"]\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\",\n          \"colors\": [\"#ff9a83\"]\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\",\n          \"colors\": [\"#ff9ba1\"]\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\",\n          \"colors\": [\"#ff7194\"]\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff0059\"]\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\",\n          \"colors\": [\"#00ffd8\"]\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue-Green\",\n          \"colors\": [\"#00ffe1\"]\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\",\n          \"colors\": [\"#ffc8de\"]\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\",\n          \"colors\": [\"#0069ff\"]\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\",\n          \"colors\": [\"#0062ff\"]\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Green\",\n          \"colors\": [\"#cfff53\"]\n        },\n        {\n          \"dmxRange\": [122, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\",\n          \"colors\": [\"#8fff60\"]\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\",\n          \"colors\": [\"#00ff66\"]\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#ff00f1\"]\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\",\n          \"colors\": [\"#ff8987\"]\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\",\n          \"colors\": [\"#ff2e9b\"]\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Heavy Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Clear\",\n          \"colors\": [\"#ffb258\"]\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\",\n          \"colors\": [\"#8fffd3\"]\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [133, 133],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\",\n          \"colors\": [\"#ff8944\"]\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Golden Amber\",\n          \"colors\": [\"#ff4200\"]\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\",\n          \"colors\": [\"#ffd0cd\"]\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\",\n          \"colors\": [\"#d6c1ff\"]\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\",\n          \"colors\": [\"#fff87c\"]\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\",\n          \"colors\": [\"#4bff00\"]\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\",\n          \"colors\": [\"#a8fffc\"]\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\",\n          \"colors\": [\"#00c8ff\"]\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\",\n          \"colors\": [\"#afaeff\"]\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\",\n          \"colors\": [\"#50e5ff\"]\n        },\n        {\n          \"dmxRange\": [144, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Blue\",\n          \"colors\": [\"#7df5ff\"]\n        },\n        {\n          \"dmxRange\": [145, 146],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\",\n          \"colors\": [\"#ffa255\"]\n        },\n        {\n          \"dmxRange\": [148, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\",\n          \"colors\": [\"#ff536c\"]\n        },\n        {\n          \"dmxRange\": [149, 150],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\",\n          \"colors\": [\"#ffb78b\"]\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\",\n          \"colors\": [\"#ffb684\"]\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\",\n          \"colors\": [\"#ffae8f\"]\n        },\n        {\n          \"dmxRange\": [154, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\",\n          \"colors\": [\"#ffbd92\"]\n        },\n        {\n          \"dmxRange\": [155, 155],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\",\n          \"colors\": [\"#ffbc77\"]\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff716e\"]\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\",\n          \"colors\": [\"#ff7800\"]\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Straw\",\n          \"colors\": [\"#ffd79c\"]\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\",\n          \"colors\": [\"#67cdff\"]\n        },\n        {\n          \"dmxRange\": [162, 162],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\",\n          \"colors\": [\"#ffc290\"]\n        },\n        {\n          \"dmxRange\": [163, 163],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\",\n          \"colors\": [\"#ff3622\"]\n        },\n        {\n          \"dmxRange\": [165, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\",\n          \"colors\": [\"#00c2ff\"]\n        },\n        {\n          \"dmxRange\": [166, 168],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\",\n          \"colors\": [\"#ffd9c1\"]\n        },\n        {\n          \"dmxRange\": [170, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\",\n          \"colors\": [\"#ffc0e1\"]\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [172, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\",\n          \"colors\": [\"#00f3ff\"]\n        },\n        {\n          \"dmxRange\": [173, 173],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\",\n          \"colors\": [\"#abe0ff\"]\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [176, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\",\n          \"colors\": [\"#ff9d75\"]\n        },\n        {\n          \"dmxRange\": [177, 178],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\",\n          \"colors\": [\"#ff9e00\"]\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\",\n          \"colors\": [\"#8866ff\"]\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\",\n          \"colors\": [\"#1a44ff\"]\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff3914\"]\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\",\n          \"colors\": [\"#00cfff\"]\n        },\n        {\n          \"dmxRange\": [184, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\",\n          \"colors\": [\"#ffd19c\"]\n        },\n        {\n          \"dmxRange\": [185, 185],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Rose\",\n          \"colors\": [\"#ffcca5\"]\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Rouge\",\n          \"colors\": [\"#ffcb97\"]\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Highlight\",\n          \"colors\": [\"#ffcf9b\"]\n        },\n        {\n          \"dmxRange\": [189, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Moss\",\n          \"colors\": [\"#ffda98\"]\n        },\n        {\n          \"dmxRange\": [190, 190],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Aqua Blue\",\n          \"colors\": [\"#ffe5b3\"]\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\",\n          \"colors\": [\"#ff7487\"]\n        },\n        {\n          \"dmxRange\": [193, 193],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\",\n          \"colors\": [\"#e5c7ff\"]\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\",\n          \"colors\": [\"#005fff\"]\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\",\n          \"colors\": [\"#64deff\"]\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\",\n          \"colors\": [\"#3aa0ff\"]\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\",\n          \"colors\": [\"#00d2ff\"]\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Regal Blue\",\n          \"colors\": [\"#2d72ff\"]\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CT Blue\",\n          \"colors\": [\"#6fbcff\"]\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Blue\",\n          \"colors\": [\"#dbf5ff\"]\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Blue\",\n          \"colors\": [\"#fffce6\"]\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Blue\",\n          \"colors\": [\"#ffe9c7\"]\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange\",\n          \"colors\": [\"#ffa955\"]\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Orange\",\n          \"colors\": [\"#ffc079\"]\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Orange\",\n          \"colors\": [\"#ffc98e\"]\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\",\n          \"colors\": [\"#ffa858\"]\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\",\n          \"colors\": [\"#ffa853\"]\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.3 Neutral Density\",\n          \"colors\": [\"#ffdcab\"]\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.6 Neutral Density\",\n          \"colors\": [\"#ffddad\"]\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.9 Neutral Density\",\n          \"colors\": [\"#ffdeaa\"]\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LCT Yellow\",\n          \"colors\": [\"#ffd68c\"]\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Flame Green\",\n          \"colors\": [\"#ffe89c\"]\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Blue\",\n          \"colors\": [\"#ffe1b7\"]\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent Green\",\n          \"colors\": [\"#a9ffc1\"]\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [221, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [222, 222],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Orange\",\n          \"colors\": [\"#ffd39b\"]\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE N.D. Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [226, 226],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE U.V.\",\n          \"colors\": [\"#ffdaa8\"]\n        },\n        {\n          \"dmxRange\": [227, 227],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brushed Silk\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Tough Spun\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [230, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Correction\",\n          \"colors\": [\"#ffc67c\"]\n        },\n        {\n          \"dmxRange\": [231, 231],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [232, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Emulated White Flame Green\",\n          \"colors\": [\"#ffad5d\"]\n        },\n        {\n          \"dmxRange\": [233, 235],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"H.M.I (To Tungsten)\",\n          \"colors\": [\"#ffa95f\"]\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.I.D. (To Tungsten)\",\n          \"colors\": [\"#ffa360\"]\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.S.I. (To Tungsten)\",\n          \"colors\": [\"#ffb483\"]\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Polariser\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 5700 K\",\n          \"colors\": [\"#ccffdc\"]\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 4300 K\",\n          \"colors\": [\"#e0ffb8\"]\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 3600 K\",\n          \"colors\": [\"#f2ffa8\"]\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Plus Green\",\n          \"colors\": [\"#ffed8f\"]\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Plus Green\",\n          \"colors\": [\"#ffe49b\"]\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Plus Green\",\n          \"colors\": [\"#ffe0a3\"]\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Minus Green\",\n          \"colors\": [\"#ffbdaa\"]\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Minus Green\",\n          \"colors\": [\"#ffccab\"]\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Minus Green\",\n          \"colors\": [\"#ffd5ad\"]\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hampshire Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"New Hampshire Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        }\n      ]\n    },\n    \"Strobe $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [7, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.4Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Static\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Static\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Static\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Static\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Fade\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Fade\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Fade\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Fade\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Simple Running\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Running\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Col Running\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flag Running\"\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Flag Running\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 4 Color\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 2 Color\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow\"\n        },\n        {\n          \"dmxRange\": [126, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [134, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor\"\n        },\n        {\n          \"dmxRange\": [142, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 2\"\n        },\n        {\n          \"dmxRange\": [150, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 4\"\n        },\n        {\n          \"dmxRange\": [172, 255],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"What happens when this capability is selected?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\"\n      }\n    },\n    \"Program Direction\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Forward with Loop\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Forward one time and stop\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Reverse one time and stop\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Reverse with Loop\"\n        }\n      ]\n    },\n    \"Program Group Size\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 group\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 groups\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 groups\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 groups\"\n        }\n      ]\n    },\n    \"Group Offset\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\",\n        \"comment\": \"Offset\"\n      }\n    },\n    \"Restart Program\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Change value to restart program\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: RGB\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"2: RGBW\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"3: RGBAW\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"4: Dim RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"5: Dim RGBW\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"6: Dim RGBAW\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"7: RGB CCT Dim Ind\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Temperature Master\",\n        \"Dimmer Master\",\n        \"LEE Color Gel Master\"\n      ]\n    },\n    {\n      \"name\": \"8: RGBS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"9: RGBWS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"10: RGBAWS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"11: Dim RGBS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"12: Dim RGBWS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"13: Dim RGBAWS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"14: RGB CCT Dim Ind S\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Temperature Master\",\n        \"Dimmer Master\",\n        \"LEE Color Gel Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"15: Effect Fix\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe Master\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade Time\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Group Offset\",\n        \"Restart Program\",\n        \"LEE Color Gel Effect Color 1\",\n        \"LEE Color Gel Effect Color 2\",\n        \"LEE Color Gel Effect Color 3\",\n        \"LEE Color Gel Effect Color 4\"\n      ]\n    },\n    {\n      \"name\": \"16: Effect RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe Master\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade Time\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Group Offset\",\n        \"Restart Program\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Effect Color 1\", \"Effect Color 2\", \"Effect Color 3\", \"Effect Color 4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"17: RGB.RGB. 4pix\",\n      \"channels\": [\n        \"Red 1/4\",\n        \"Green 1/4\",\n        \"Blue 1/4\",\n        null,\n        \"Red 2/4\",\n        \"Green 2/4\",\n        \"Blue 2/4\",\n        null,\n        \"Red 3/4\",\n        \"Green 3/4\",\n        \"Blue 3/4\",\n        null,\n        \"Red 4/4\",\n        \"Green 4/4\",\n        \"Blue 4/4\"\n      ]\n    },\n    {\n      \"name\": \"18: RGB RGB 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"19: RGBW RGBW 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"20: RGBAW RGBAW 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"21: Dim RGB Dim RGB 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"22: Dim RGBW Dim RGBW 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"23: Dim RGBAW Dim RGBAW 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"24: RGB CCT Dim Ind 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"25: RGB.RGBS 4pix\",\n      \"channels\": [\n        \"Red 1/4\",\n        \"Green 1/4\",\n        \"Blue 1/4\",\n        \"Strobe Master\",\n        \"Red 2/4\",\n        \"Green 2/4\",\n        \"Blue 2/4\",\n        null,\n        \"Red 3/4\",\n        \"Green 3/4\",\n        \"Blue 3/4\",\n        null,\n        \"Red 4/4\",\n        \"Green 4/4\",\n        \"Blue 4/4\"\n      ]\n    },\n    {\n      \"name\": \"26: RGB RGB .. S 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"27: RGBW RGBW .. S 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"28: RGBAW RGBAW .. S 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"29: Dim RGB Dim RGB .. S 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"30: Dim RGBW Dim RGBW .. S 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"31: Dim RGBAW Dim RGBAW .. S 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"32: RGB CCT Dim Ind S 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"33: RGBSRGBS 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"34: RGB RGB .. SS 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"35: RGBWS RGBWS 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"36: RGBAWS RGBAWS 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"37: Dim RGBS Dim RGBS 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"38: Dim RGBWS Dim RGBWS 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"39: Dim RGBAWS Dim RGBAWS 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"40: RGB CCT Dim Ind S 4pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"41: RGB.RGB. 16pix\",\n      \"channels\": [\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        null,\n        \"Red 2\",\n        \"Green 2\",\n        \"Blue 2\",\n        null,\n        \"Red 3\",\n        \"Green 3\",\n        \"Blue 3\",\n        null,\n        \"Red 4\",\n        \"Green 4\",\n        \"Blue 4\",\n        null,\n        \"Red 5\",\n        \"Green 5\",\n        \"Blue 5\",\n        null,\n        \"Red 6\",\n        \"Green 6\",\n        \"Blue 6\",\n        null,\n        \"Red 7\",\n        \"Green 7\",\n        \"Blue 7\",\n        null,\n        \"Red 8\",\n        \"Green 8\",\n        \"Blue 8\",\n        null,\n        \"Red 9\",\n        \"Green 9\",\n        \"Blue 9\",\n        null,\n        \"Red 10\",\n        \"Green 10\",\n        \"Blue 10\",\n        null,\n        \"Red 11\",\n        \"Green 11\",\n        \"Blue 11\",\n        null,\n        \"Red 12\",\n        \"Green 12\",\n        \"Blue 12\",\n        null,\n        \"Red 13\",\n        \"Green 13\",\n        \"Blue 13\",\n        null,\n        \"Red 14\",\n        \"Green 14\",\n        \"Blue 14\",\n        null,\n        \"Red 15\",\n        \"Green 15\",\n        \"Blue 15\",\n        null,\n        \"Red 16\",\n        \"Green 16\",\n        \"Blue 16\"\n      ]\n    },\n    {\n      \"name\": \"42: RGB RGB 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"43: RGBW RGBW 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"44: RGBAW RGBAW 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"45: Dim RGB Dim RGB 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"46: Dim RGBW Dim RGBW 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"47: Dim RGBAW Dim RGBAW 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"48: RGB CCT Dim Ind 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"49: RGB.RGBS 16pix\",\n      \"channels\": [\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        \"Strobe Master\",\n        \"Red 2\",\n        \"Green 2\",\n        \"Blue 2\",\n        null,\n        \"Red 3\",\n        \"Green 3\",\n        \"Blue 3\",\n        null,\n        \"Red 4\",\n        \"Green 4\",\n        \"Blue 4\",\n        null,\n        \"Red 5\",\n        \"Green 5\",\n        \"Blue 5\",\n        null,\n        \"Red 6\",\n        \"Green 6\",\n        \"Blue 6\",\n        null,\n        \"Red 7\",\n        \"Green 7\",\n        \"Blue 7\",\n        null,\n        \"Red 8\",\n        \"Green 8\",\n        \"Blue 8\",\n        null,\n        \"Red 9\",\n        \"Green 9\",\n        \"Blue 9\",\n        null,\n        \"Red 10\",\n        \"Green 10\",\n        \"Blue 10\",\n        null,\n        \"Red 11\",\n        \"Green 11\",\n        \"Blue 11\",\n        null,\n        \"Red 12\",\n        \"Green 12\",\n        \"Blue 12\",\n        null,\n        \"Red 13\",\n        \"Green 13\",\n        \"Blue 13\",\n        null,\n        \"Red 14\",\n        \"Green 14\",\n        \"Blue 14\",\n        null,\n        \"Red 15\",\n        \"Green 15\",\n        \"Blue 15\",\n        null,\n        \"Red 16\",\n        \"Green 16\",\n        \"Blue 16\"\n      ]\n    },\n    {\n      \"name\": \"50: RGB RGB .. S 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"51: RGBW RGBW .. S 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"52: RGBAW RGBAW .. S 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"53: Dim RGB Dim RGB .. S 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"54: Dim RGBW Dim RGBW .. S 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"55: Dim RGBAW Dim RGBAW .. S 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"56: RGB CCT Dim Ind S 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"57: RGBSRGBS 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"58: RGB RGB .. SS 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"59: RGBWS RGBWS 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"60: RGBAWS RGBAWS 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"61: Dim RGBS Dim RGBS 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"62: Dim RGBWS Dim RGBWS 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"63: Dim RGBAWS Dim RGBAWS 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"64: RGB CCT Dim Ind S 16pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"89: D CCT GM CRO RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Crossfade Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"90: D CCT GM HUE SAT\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Hue Master\",\n        \"Saturation Master\"\n      ]\n    },\n    {\n      \"name\": \"91: D16 CCT GM CRO RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Dimmer Master fine\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Crossfade Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"92: D16 CCT GM H SAT\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Dimmer Master fine\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Hue Master\",\n        \"Hue Master fine\",\n        \"Saturation Master\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/astera/fp2-helios-tube.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"FP2 Helios Tube\",\n  \"shortName\": \"AsteraFP2Helios\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\", \"Blinder\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jack Crombie\", \"Felix Edelmann\", \"Dyami Caliri\"],\n    \"createDate\": \"2021-01-11\",\n    \"lastModifyDate\": \"2021-01-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://astera-led.com/Downloads/Profile/Helios%20Tube%20DMX%20Profiles.pdf\"\n    ],\n    \"productPage\": [\n      \"https://astera-led.com/products/helios-tube/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=BXILas0oABk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [550, 42, 42],\n    \"weight\": 0.765,\n    \"power\": 24,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 1340\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [64, 42, 42],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [8, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": { \"x\": [\"<=4\"] },\n      \"2/2\": { \"x\": [\">=5\", \"<=8\"] },\n      \"Effect Color 1\": \"all\",\n      \"Effect Color 2\": \"all\",\n      \"Effect Color 3\": \"all\",\n      \"Effect Color 4\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"fineChannelAliases\": [\"Dimmer $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Emulated White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2100K\",\n          \"colorTemperatureEnd\": \"7100K\",\n          \"helpWanted\": \"Does this capability already begin at DMX value 4 (with 2080K)?\"\n        }\n      ]\n    },\n    \"CCT $pixelKey\": {\n      \"capability\":\n        {\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1750K\",\n          \"colorTemperatureEnd\": \"9910K\"\n        }\n    },\n    \"Crossfade $pixelKey\": {\n      \"capability\":\n        {\n          \"type\": \"Generic\",\n          \"comment\": \"CCT crossfade to RGB\"\n        }\n    },\n    \"Green-Magenta Point $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…100%\"\n        }\n      ]\n    },\n    \"Hue $pixelKey\": {\n      \"fineChannelAliases\": [\"Hue $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"LEE Color Gel $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\",\n          \"colors\": [\"#ff8fb9\"]\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\",\n          \"colors\": [\"#ffdab5\"]\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Bastard Amber\",\n          \"colors\": [\"#ffb783\"]\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\",\n          \"colors\": [\"#ffd78c\"]\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\",\n          \"colors\": [\"#ff814c\"]\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\",\n          \"colors\": [\"#ffc176\"]\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\",\n          \"colors\": [\"#ffd21c\"]\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\",\n          \"colors\": [\"#ffc069\"]\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\",\n          \"colors\": [\"#ff9f00\"]\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\",\n          \"colors\": [\"#ffa25b\"]\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\",\n          \"colors\": [\"#ff391b\"]\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\",\n          \"colors\": [\"#ff9123\"]\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\",\n          \"colors\": [\"#ff7600\"]\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\",\n          \"colors\": [\"#ff4f0a\"]\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\",\n          \"colors\": [\"#ff5647\"]\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\",\n          \"colors\": [\"#ff6f2f\"]\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\",\n          \"colors\": [\"#ff0012\"]\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\",\n          \"colors\": [\"#ff0020\"]\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Plasa Red\",\n          \"colors\": [\"#ff2707\"]\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#ffbaa1\"]\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\",\n          \"colors\": [\"#ff9f98\"]\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\",\n          \"colors\": [\"#ff0055\"]\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\",\n          \"colors\": [\"#ff95e0\"]\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Purple\",\n          \"colors\": [\"#ff50f1\"]\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\",\n          \"colors\": [\"#ffdcf6\"]\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\",\n          \"colors\": [\"#ffe5ca\"]\n        },\n        {\n          \"dmxRange\": [54, 57],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#af7cff\"]\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\",\n          \"colors\": [\"#fff9db\"]\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\",\n          \"colors\": [\"#f6ffeb\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#00acff\"]\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tokyo Blue\",\n          \"colors\": [\"#0040ff\"]\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Evening Blue\",\n          \"colors\": [\"#00a1ff\"]\n        },\n        {\n          \"dmxRange\": [76, 78],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\",\n          \"colors\": [\"#007bff\"]\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\",\n          \"colors\": [\"#0075ff\"]\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\",\n          \"colors\": [\"#fffe4c\"]\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\",\n          \"colors\": [\"#a7ff58\"]\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Yellow Green\",\n          \"colors\": [\"#3aff42\"]\n        },\n        {\n          \"dmxRange\": [91, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\",\n          \"colors\": [\"#ffd930\"]\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffc600\"]\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\",\n          \"colors\": [\"#ffba45\"]\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\",\n          \"colors\": [\"#ffd88f\"]\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\",\n          \"colors\": [\"#ffa704\"]\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8700\"]\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\",\n          \"colors\": [\"#ff0018\"]\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\",\n          \"colors\": [\"#ff8d7e\"]\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\",\n          \"colors\": [\"#ffa76b\"]\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\",\n          \"colors\": [\"#ff9a83\"]\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\",\n          \"colors\": [\"#ff9ba1\"]\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\",\n          \"colors\": [\"#ff7194\"]\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff0059\"]\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\",\n          \"colors\": [\"#00ffd8\"]\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue-Green\",\n          \"colors\": [\"#00ffe1\"]\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\",\n          \"colors\": [\"#ffc8de\"]\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\",\n          \"colors\": [\"#0069ff\"]\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\",\n          \"colors\": [\"#0062ff\"]\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Green\",\n          \"colors\": [\"#cfff53\"]\n        },\n        {\n          \"dmxRange\": [122, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\",\n          \"colors\": [\"#8fff60\"]\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\",\n          \"colors\": [\"#00ff66\"]\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#ff00f1\"]\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\",\n          \"colors\": [\"#ff8987\"]\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\",\n          \"colors\": [\"#ff2e9b\"]\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Heavy Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Clear\",\n          \"colors\": [\"#ffb258\"]\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\",\n          \"colors\": [\"#8fffd3\"]\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [133, 133],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\",\n          \"colors\": [\"#ff8944\"]\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Golden Amber\",\n          \"colors\": [\"#ff4200\"]\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\",\n          \"colors\": [\"#ffd0cd\"]\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\",\n          \"colors\": [\"#d6c1ff\"]\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\",\n          \"colors\": [\"#fff87c\"]\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\",\n          \"colors\": [\"#4bff00\"]\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\",\n          \"colors\": [\"#a8fffc\"]\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\",\n          \"colors\": [\"#00c8ff\"]\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\",\n          \"colors\": [\"#afaeff\"]\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\",\n          \"colors\": [\"#50e5ff\"]\n        },\n        {\n          \"dmxRange\": [144, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Blue\",\n          \"colors\": [\"#7df5ff\"]\n        },\n        {\n          \"dmxRange\": [145, 146],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\",\n          \"colors\": [\"#ffa255\"]\n        },\n        {\n          \"dmxRange\": [148, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\",\n          \"colors\": [\"#ff536c\"]\n        },\n        {\n          \"dmxRange\": [149, 150],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\",\n          \"colors\": [\"#ffb78b\"]\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\",\n          \"colors\": [\"#ffb684\"]\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\",\n          \"colors\": [\"#ffae8f\"]\n        },\n        {\n          \"dmxRange\": [154, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\",\n          \"colors\": [\"#ffbd92\"]\n        },\n        {\n          \"dmxRange\": [155, 155],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\",\n          \"colors\": [\"#ffbc77\"]\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff716e\"]\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\",\n          \"colors\": [\"#ff7800\"]\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Straw\",\n          \"colors\": [\"#ffd79c\"]\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\",\n          \"colors\": [\"#67cdff\"]\n        },\n        {\n          \"dmxRange\": [162, 162],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\",\n          \"colors\": [\"#ffc290\"]\n        },\n        {\n          \"dmxRange\": [163, 163],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\",\n          \"colors\": [\"#ff3622\"]\n        },\n        {\n          \"dmxRange\": [165, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\",\n          \"colors\": [\"#00c2ff\"]\n        },\n        {\n          \"dmxRange\": [166, 168],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\",\n          \"colors\": [\"#ffd9c1\"]\n        },\n        {\n          \"dmxRange\": [170, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\",\n          \"colors\": [\"#ffc0e1\"]\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [172, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\",\n          \"colors\": [\"#00f3ff\"]\n        },\n        {\n          \"dmxRange\": [173, 173],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\",\n          \"colors\": [\"#abe0ff\"]\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [176, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\",\n          \"colors\": [\"#ff9d75\"]\n        },\n        {\n          \"dmxRange\": [177, 178],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\",\n          \"colors\": [\"#ff9e00\"]\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\",\n          \"colors\": [\"#8866ff\"]\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\",\n          \"colors\": [\"#1a44ff\"]\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff3914\"]\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\",\n          \"colors\": [\"#00cfff\"]\n        },\n        {\n          \"dmxRange\": [184, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\",\n          \"colors\": [\"#ffd19c\"]\n        },\n        {\n          \"dmxRange\": [185, 185],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Rose\",\n          \"colors\": [\"#ffcca5\"]\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Rouge\",\n          \"colors\": [\"#ffcb97\"]\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Highlight\",\n          \"colors\": [\"#ffcf9b\"]\n        },\n        {\n          \"dmxRange\": [189, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Moss\",\n          \"colors\": [\"#ffda98\"]\n        },\n        {\n          \"dmxRange\": [190, 190],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Aqua Blue\",\n          \"colors\": [\"#ffe5b3\"]\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\",\n          \"colors\": [\"#ff7487\"]\n        },\n        {\n          \"dmxRange\": [193, 193],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\",\n          \"colors\": [\"#e5c7ff\"]\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\",\n          \"colors\": [\"#005fff\"]\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\",\n          \"colors\": [\"#64deff\"]\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\",\n          \"colors\": [\"#3aa0ff\"]\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\",\n          \"colors\": [\"#00d2ff\"]\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Regal Blue\",\n          \"colors\": [\"#2d72ff\"]\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CT Blue\",\n          \"colors\": [\"#6fbcff\"]\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Blue\",\n          \"colors\": [\"#dbf5ff\"]\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Blue\",\n          \"colors\": [\"#fffce6\"]\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Blue\",\n          \"colors\": [\"#ffe9c7\"]\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange\",\n          \"colors\": [\"#ffa955\"]\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Orange\",\n          \"colors\": [\"#ffc079\"]\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Orange\",\n          \"colors\": [\"#ffc98e\"]\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\",\n          \"colors\": [\"#ffa858\"]\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\",\n          \"colors\": [\"#ffa853\"]\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.3 Neutral Density\",\n          \"colors\": [\"#ffdcab\"]\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.6 Neutral Density\",\n          \"colors\": [\"#ffddad\"]\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.9 Neutral Density\",\n          \"colors\": [\"#ffdeaa\"]\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LCT Yellow\",\n          \"colors\": [\"#ffd68c\"]\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Flame Green\",\n          \"colors\": [\"#ffe89c\"]\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Blue\",\n          \"colors\": [\"#ffe1b7\"]\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent Green\",\n          \"colors\": [\"#a9ffc1\"]\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [221, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [222, 222],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Orange\",\n          \"colors\": [\"#ffd39b\"]\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE N.D. Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [226, 226],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE U.V.\",\n          \"colors\": [\"#ffdaa8\"]\n        },\n        {\n          \"dmxRange\": [227, 227],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brushed Silk\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Tough Spun\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [230, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Correction\",\n          \"colors\": [\"#ffc67c\"]\n        },\n        {\n          \"dmxRange\": [231, 231],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [232, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Emulated White Flame Green\",\n          \"colors\": [\"#ffad5d\"]\n        },\n        {\n          \"dmxRange\": [233, 235],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"H.M.I (To Tungsten)\",\n          \"colors\": [\"#ffa95f\"]\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.I.D. (To Tungsten)\",\n          \"colors\": [\"#ffa360\"]\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.S.I. (To Tungsten)\",\n          \"colors\": [\"#ffb483\"]\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Polariser\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 5700 K\",\n          \"colors\": [\"#ccffdc\"]\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 4300 K\",\n          \"colors\": [\"#e0ffb8\"]\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 3600 K\",\n          \"colors\": [\"#f2ffa8\"]\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Plus Green\",\n          \"colors\": [\"#ffed8f\"]\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Plus Green\",\n          \"colors\": [\"#ffe49b\"]\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Plus Green\",\n          \"colors\": [\"#ffe0a3\"]\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Minus Green\",\n          \"colors\": [\"#ffbdaa\"]\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Minus Green\",\n          \"colors\": [\"#ffccab\"]\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Minus Green\",\n          \"colors\": [\"#ffd5ad\"]\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hampshire Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"New Hampshire Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        }\n      ]\n    },\n    \"Strobe $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [7, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.4Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Static\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Static\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Static\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Static\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Fade\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Fade\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Fade\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Fade\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Simple Running\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Running\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Col Running\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flag Running\"\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Flag Running\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 4 Color\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 2 Color\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow\"\n        },\n        {\n          \"dmxRange\": [126, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [134, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor\"\n        },\n        {\n          \"dmxRange\": [142, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 2\"\n        },\n        {\n          \"dmxRange\": [150, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 4\"\n        },\n        {\n          \"dmxRange\": [172, 255],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"What happens when this capability is selected?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\"\n      }\n    },\n    \"Program Direction\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Forward with Loop\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Forward one time and stop\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Reverse one time and stop\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Reverse with Loop\"\n        }\n      ]\n    },\n    \"Program Group Size\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 group\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 groups\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 groups\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 groups\"\n        }\n      ]\n    },\n    \"Group Offset\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\",\n        \"comment\": \"Offset\"\n      }\n    },\n    \"Restart Program\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Change value to restart program\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: RGB\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"2: RGBW\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"3: RGBAW\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"4: Dim RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"5: Dim RGBW\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"6: Dim RGBAW\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"7: RGB CCT Dim Ind\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Temperature Master\",\n        \"Dimmer Master\",\n        \"LEE Color Gel Master\"\n      ]\n    },\n    {\n      \"name\": \"8: RGBS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"9: RGBWS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"10: RGBAWS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"11: Dim RGBS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"12: Dim RGBWS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"13: Dim RGBAWS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"14: RGB CCT Dim Ind S\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Temperature Master\",\n        \"Dimmer Master\",\n        \"LEE Color Gel Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"15: Effect Fix\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe Master\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade Time\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Group Offset\",\n        \"Restart Program\",\n        \"LEE Color Gel Effect Color 1\",\n        \"LEE Color Gel Effect Color 2\",\n        \"LEE Color Gel Effect Color 3\",\n        \"LEE Color Gel Effect Color 4\"\n      ]\n    },\n    {\n      \"name\": \"16: Effect RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe Master\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade Time\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Group Offset\",\n        \"Restart Program\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Effect Color 1\", \"Effect Color 2\", \"Effect Color 3\", \"Effect Color 4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"17: RGB.RGB.  2pix\",\n      \"channels\": [\n        \"Red 1/2\",\n        \"Green 1/2\",\n        \"Blue 1/2\",\n        null,\n        \"Red 2/2\",\n        \"Green 2/2\",\n        \"Blue 2/2\"\n      ]\n    },\n    {\n      \"name\": \"18: RGB RGB  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"19: RGBW RGBW  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"20: RGBAW RGBAW  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"21: Dim RGB Dim RGB  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"22: Dim RGBW Dim RGBW  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"23: Dim RGBAW Dim RGBAW  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"24: RGB CCT Dim Ind  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"25: RGB.RGBS  2pix\",\n      \"channels\": [\n        \"Red 1/2\",\n        \"Green 1/2\",\n        \"Blue 1/2\",\n        \"Strobe Master\",\n        \"Red 2/2\",\n        \"Green 2/2\",\n        \"Blue 2/2\"\n      ]\n    },\n    {\n      \"name\": \"26: RGB RGB .. S  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"27: RGBW RGBW .. S  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"28: RGBAW RGBAW .. S  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"29: Dim RGB Dim RGB .. S  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"30: Dim RGBW Dim RGBW .. S  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"31: Dim RGBAW Dim RGBAW .. S  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"32: RGB CCT Dim Ind S  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"33: RGBSRGBS  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"34: RGB RGB .. SS  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"35: RGBWS RGBWS  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"36: RGBAWS RGBAWS  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"37: Dim RGBS Dim RGBS  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"38: Dim RGBWS Dim RGBWS  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"39: Dim RGBAWS Dim RGBAWS  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"40: RGB CCT Dim Ind S  2pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"41: RGB.RGB. 8pix\",\n      \"channels\": [\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        null,\n        \"Red 2\",\n        \"Green 2\",\n        \"Blue 2\",\n        null,\n        \"Red 3\",\n        \"Green 3\",\n        \"Blue 3\",\n        null,\n        \"Red 4\",\n        \"Green 4\",\n        \"Blue 4\",\n        null,\n        \"Red 5\",\n        \"Green 5\",\n        \"Blue 5\",\n        null,\n        \"Red 6\",\n        \"Green 6\",\n        \"Blue 6\",\n        null,\n        \"Red 7\",\n        \"Green 7\",\n        \"Blue 7\",\n        null,\n        \"Red 8\",\n        \"Green 8\",\n        \"Blue 8\"\n      ]\n    },\n    {\n      \"name\": \"42: RGB RGB 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"43: RGBW RGBW 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"44: RGBAW RGBAW 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"45: Dim RGB Dim RGB 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"46: Dim RGBW Dim RGBW 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"47: Dim RGBAW Dim RGBAW 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"48: RGB CCT Dim Ind 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"49: RGB.RGBS 8pix\",\n      \"channels\": [\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        \"Strobe Master\",\n        \"Red 2\",\n        \"Green 2\",\n        \"Blue 2\",\n        null,\n        \"Red 3\",\n        \"Green 3\",\n        \"Blue 3\",\n        null,\n        \"Red 4\",\n        \"Green 4\",\n        \"Blue 4\",\n        null,\n        \"Red 5\",\n        \"Green 5\",\n        \"Blue 5\",\n        null,\n        \"Red 6\",\n        \"Green 6\",\n        \"Blue 6\",\n        null,\n        \"Red 7\",\n        \"Green 7\",\n        \"Blue 7\",\n        null,\n        \"Red 8\",\n        \"Green 8\",\n        \"Blue 8\"\n      ]\n    },\n    {\n      \"name\": \"50: RGB RGB .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"51: RGBW RGBW .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"52: RGBAW RGBAW .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"53: Dim RGB Dim RGB .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"54: Dim RGBW Dim RGBW .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"55: Dim RGBAW Dim RGBAW .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"56: RGB CCT Dim Ind S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"57: RGBSRGBS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"58: RGB RGB .. SS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"59: RGBWS RGBWS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"60: RGBAWS RGBAWS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"61: Dim RGBS Dim RGBS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"62: Dim RGBWS Dim RGBWS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"63: Dim RGBAWS Dim RGBAWS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"64: RGB CCT Dim Ind S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"89: D CCT GM CRO RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Crossfade Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"90: D CCT GM HUE SAT\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Hue Master\",\n        \"Saturation Master\"\n      ]\n    },\n    {\n      \"name\": \"91: D16 CCT GM CRO RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Dimmer Master fine\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Crossfade Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"92: D16 CCT GM H SAT\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Dimmer Master fine\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Hue Master\",\n        \"Hue Master fine\",\n        \"Saturation Master\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/astera/fp3-hyperion-tube.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"FP3 Hyperion Tube\",\n  \"shortName\": \"AsteraFP3Hyperion\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\", \"Blinder\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jack Crombie\", \"Felix Edelmann\", \"Dyami Caliri\", \"Ryan Goodwin\"],\n    \"createDate\": \"2021-01-11\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://astera-led.com/Downloads/Profile/Hyperion%20Tube%20DMX%20Profiles.pdf\"\n    ],\n    \"productPage\": [\n      \"https://astera-led.com/products/hyperion-tube/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ZEkDgApXaDg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [2031, 42, 42],\n    \"weight\": 2.9,\n    \"power\": 92,\n    \"powerConnectors\": {\n      \"Proprietary\": \"input only\"\n    },\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 5800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [64, 42, 42],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [32, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/8\": { \"x\": [\"<=4\"] },\n      \"2/8\": { \"x\": [\">=5\", \"<=8\"] },\n      \"3/8\": { \"x\": [\">=9\", \"<=12\"] },\n      \"4/8\": { \"x\": [\">=13\", \"<=16\"] },\n      \"5/8\": { \"x\": [\">=17\", \"<=20\"] },\n      \"6/8\": { \"x\": [\">=21\", \"<=24\"] },\n      \"7/8\": { \"x\": [\">=25\", \"<=28\"] },\n      \"8/8\": { \"x\": [\"<=32\"] },\n      \"Effect Color 1\": \"all\",\n      \"Effect Color 2\": \"all\",\n      \"Effect Color 3\": \"all\",\n      \"Effect Color 4\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"fineChannelAliases\": [\"Dimmer $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Emulated White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2100K\",\n          \"colorTemperatureEnd\": \"7100K\",\n          \"helpWanted\": \"Does this capability already begin at DMX value 4 (with 2080K)?\"\n        }\n      ]\n    },\n    \"CCT $pixelKey\": {\n      \"capability\":\n        {\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1750K\",\n          \"colorTemperatureEnd\": \"9910K\"\n        }\n    },\n    \"Crossfade $pixelKey\": {\n      \"capability\":\n        {\n          \"type\": \"Generic\",\n          \"comment\": \"CCT crossfade to RGB\"\n        }\n    },\n    \"Green-Magenta Point $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…100%\"\n        }\n      ]\n    },\n    \"Hue $pixelKey\": {\n      \"fineChannelAliases\": [\"Hue $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"LEE Color Gel $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\",\n          \"colors\": [\"#ff8fb9\"]\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\",\n          \"colors\": [\"#ffdab5\"]\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Bastard Amber\",\n          \"colors\": [\"#ffb783\"]\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\",\n          \"colors\": [\"#ffd78c\"]\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\",\n          \"colors\": [\"#ff814c\"]\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\",\n          \"colors\": [\"#ffc176\"]\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\",\n          \"colors\": [\"#ffd21c\"]\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\",\n          \"colors\": [\"#ffc069\"]\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\",\n          \"colors\": [\"#ff9f00\"]\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\",\n          \"colors\": [\"#ffa25b\"]\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\",\n          \"colors\": [\"#ff391b\"]\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\",\n          \"colors\": [\"#ff9123\"]\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\",\n          \"colors\": [\"#ff7600\"]\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\",\n          \"colors\": [\"#ff4f0a\"]\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\",\n          \"colors\": [\"#ff5647\"]\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\",\n          \"colors\": [\"#ff6f2f\"]\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\",\n          \"colors\": [\"#ff0012\"]\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\",\n          \"colors\": [\"#ff0020\"]\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Plasa Red\",\n          \"colors\": [\"#ff2707\"]\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#ffbaa1\"]\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\",\n          \"colors\": [\"#ff9f98\"]\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\",\n          \"colors\": [\"#ff0055\"]\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\",\n          \"colors\": [\"#ff95e0\"]\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Purple\",\n          \"colors\": [\"#ff50f1\"]\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\",\n          \"colors\": [\"#ffdcf6\"]\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\",\n          \"colors\": [\"#ffe5ca\"]\n        },\n        {\n          \"dmxRange\": [54, 57],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#af7cff\"]\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\",\n          \"colors\": [\"#fff9db\"]\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\",\n          \"colors\": [\"#f6ffeb\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#00acff\"]\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tokyo Blue\",\n          \"colors\": [\"#0040ff\"]\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Evening Blue\",\n          \"colors\": [\"#00a1ff\"]\n        },\n        {\n          \"dmxRange\": [76, 78],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\",\n          \"colors\": [\"#007bff\"]\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\",\n          \"colors\": [\"#0075ff\"]\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\",\n          \"colors\": [\"#fffe4c\"]\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\",\n          \"colors\": [\"#a7ff58\"]\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Yellow Green\",\n          \"colors\": [\"#3aff42\"]\n        },\n        {\n          \"dmxRange\": [91, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\",\n          \"colors\": [\"#ffd930\"]\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffc600\"]\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\",\n          \"colors\": [\"#ffba45\"]\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\",\n          \"colors\": [\"#ffd88f\"]\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\",\n          \"colors\": [\"#ffa704\"]\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8700\"]\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\",\n          \"colors\": [\"#ff0018\"]\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\",\n          \"colors\": [\"#ff8d7e\"]\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\",\n          \"colors\": [\"#ffa76b\"]\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\",\n          \"colors\": [\"#ff9a83\"]\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\",\n          \"colors\": [\"#ff9ba1\"]\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\",\n          \"colors\": [\"#ff7194\"]\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff0059\"]\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\",\n          \"colors\": [\"#00ffd8\"]\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue-Green\",\n          \"colors\": [\"#00ffe1\"]\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\",\n          \"colors\": [\"#ffc8de\"]\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\",\n          \"colors\": [\"#0069ff\"]\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\",\n          \"colors\": [\"#0062ff\"]\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Green\",\n          \"colors\": [\"#cfff53\"]\n        },\n        {\n          \"dmxRange\": [122, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\",\n          \"colors\": [\"#8fff60\"]\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\",\n          \"colors\": [\"#00ff66\"]\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#ff00f1\"]\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\",\n          \"colors\": [\"#ff8987\"]\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\",\n          \"colors\": [\"#ff2e9b\"]\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Heavy Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Clear\",\n          \"colors\": [\"#ffb258\"]\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\",\n          \"colors\": [\"#8fffd3\"]\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [133, 133],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\",\n          \"colors\": [\"#ff8944\"]\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Golden Amber\",\n          \"colors\": [\"#ff4200\"]\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\",\n          \"colors\": [\"#ffd0cd\"]\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\",\n          \"colors\": [\"#d6c1ff\"]\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\",\n          \"colors\": [\"#fff87c\"]\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\",\n          \"colors\": [\"#4bff00\"]\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\",\n          \"colors\": [\"#a8fffc\"]\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\",\n          \"colors\": [\"#00c8ff\"]\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\",\n          \"colors\": [\"#afaeff\"]\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\",\n          \"colors\": [\"#50e5ff\"]\n        },\n        {\n          \"dmxRange\": [144, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Blue\",\n          \"colors\": [\"#7df5ff\"]\n        },\n        {\n          \"dmxRange\": [145, 146],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\",\n          \"colors\": [\"#ffa255\"]\n        },\n        {\n          \"dmxRange\": [148, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\",\n          \"colors\": [\"#ff536c\"]\n        },\n        {\n          \"dmxRange\": [149, 150],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\",\n          \"colors\": [\"#ffb78b\"]\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\",\n          \"colors\": [\"#ffb684\"]\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\",\n          \"colors\": [\"#ffae8f\"]\n        },\n        {\n          \"dmxRange\": [154, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\",\n          \"colors\": [\"#ffbd92\"]\n        },\n        {\n          \"dmxRange\": [155, 155],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\",\n          \"colors\": [\"#ffbc77\"]\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff716e\"]\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\",\n          \"colors\": [\"#ff7800\"]\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Straw\",\n          \"colors\": [\"#ffd79c\"]\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\",\n          \"colors\": [\"#67cdff\"]\n        },\n        {\n          \"dmxRange\": [162, 162],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\",\n          \"colors\": [\"#ffc290\"]\n        },\n        {\n          \"dmxRange\": [163, 163],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\",\n          \"colors\": [\"#ff3622\"]\n        },\n        {\n          \"dmxRange\": [165, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\",\n          \"colors\": [\"#00c2ff\"]\n        },\n        {\n          \"dmxRange\": [166, 168],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\",\n          \"colors\": [\"#ffd9c1\"]\n        },\n        {\n          \"dmxRange\": [170, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\",\n          \"colors\": [\"#ffc0e1\"]\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [172, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\",\n          \"colors\": [\"#00f3ff\"]\n        },\n        {\n          \"dmxRange\": [173, 173],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\",\n          \"colors\": [\"#abe0ff\"]\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [176, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\",\n          \"colors\": [\"#ff9d75\"]\n        },\n        {\n          \"dmxRange\": [177, 178],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\",\n          \"colors\": [\"#ff9e00\"]\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\",\n          \"colors\": [\"#8866ff\"]\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\",\n          \"colors\": [\"#1a44ff\"]\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff3914\"]\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\",\n          \"colors\": [\"#00cfff\"]\n        },\n        {\n          \"dmxRange\": [184, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\",\n          \"colors\": [\"#ffd19c\"]\n        },\n        {\n          \"dmxRange\": [185, 185],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Rose\",\n          \"colors\": [\"#ffcca5\"]\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Rouge\",\n          \"colors\": [\"#ffcb97\"]\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Highlight\",\n          \"colors\": [\"#ffcf9b\"]\n        },\n        {\n          \"dmxRange\": [189, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Moss\",\n          \"colors\": [\"#ffda98\"]\n        },\n        {\n          \"dmxRange\": [190, 190],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Aqua Blue\",\n          \"colors\": [\"#ffe5b3\"]\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\",\n          \"colors\": [\"#ff7487\"]\n        },\n        {\n          \"dmxRange\": [193, 193],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\",\n          \"colors\": [\"#e5c7ff\"]\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\",\n          \"colors\": [\"#005fff\"]\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\",\n          \"colors\": [\"#64deff\"]\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\",\n          \"colors\": [\"#3aa0ff\"]\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\",\n          \"colors\": [\"#00d2ff\"]\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Regal Blue\",\n          \"colors\": [\"#2d72ff\"]\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CT Blue\",\n          \"colors\": [\"#6fbcff\"]\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Blue\",\n          \"colors\": [\"#dbf5ff\"]\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Blue\",\n          \"colors\": [\"#fffce6\"]\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Blue\",\n          \"colors\": [\"#ffe9c7\"]\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange\",\n          \"colors\": [\"#ffa955\"]\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Orange\",\n          \"colors\": [\"#ffc079\"]\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Orange\",\n          \"colors\": [\"#ffc98e\"]\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\",\n          \"colors\": [\"#ffa858\"]\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\",\n          \"colors\": [\"#ffa853\"]\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.3 Neutral Density\",\n          \"colors\": [\"#ffdcab\"]\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.6 Neutral Density\",\n          \"colors\": [\"#ffddad\"]\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.9 Neutral Density\",\n          \"colors\": [\"#ffdeaa\"]\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LCT Yellow\",\n          \"colors\": [\"#ffd68c\"]\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Flame Green\",\n          \"colors\": [\"#ffe89c\"]\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Blue\",\n          \"colors\": [\"#ffe1b7\"]\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent Green\",\n          \"colors\": [\"#a9ffc1\"]\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [221, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [222, 222],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Orange\",\n          \"colors\": [\"#ffd39b\"]\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE N.D. Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [226, 226],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE U.V.\",\n          \"colors\": [\"#ffdaa8\"]\n        },\n        {\n          \"dmxRange\": [227, 227],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brushed Silk\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Tough Spun\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [230, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Correction\",\n          \"colors\": [\"#ffc67c\"]\n        },\n        {\n          \"dmxRange\": [231, 231],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [232, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Emulated White Flame Green\",\n          \"colors\": [\"#ffad5d\"]\n        },\n        {\n          \"dmxRange\": [233, 235],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"H.M.I (To Tungsten)\",\n          \"colors\": [\"#ffa95f\"]\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.I.D. (To Tungsten)\",\n          \"colors\": [\"#ffa360\"]\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.S.I. (To Tungsten)\",\n          \"colors\": [\"#ffb483\"]\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Polariser\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 5700 K\",\n          \"colors\": [\"#ccffdc\"]\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 4300 K\",\n          \"colors\": [\"#e0ffb8\"]\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 3600 K\",\n          \"colors\": [\"#f2ffa8\"]\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Plus Green\",\n          \"colors\": [\"#ffed8f\"]\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Plus Green\",\n          \"colors\": [\"#ffe49b\"]\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Plus Green\",\n          \"colors\": [\"#ffe0a3\"]\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Minus Green\",\n          \"colors\": [\"#ffbdaa\"]\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Minus Green\",\n          \"colors\": [\"#ffccab\"]\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Minus Green\",\n          \"colors\": [\"#ffd5ad\"]\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hampshire Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"New Hampshire Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        }\n      ]\n    },\n    \"Strobe $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [7, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.4Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Static\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Static\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Static\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Static\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Fade\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Fade\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Fade\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Fade\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Simple Running\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Running\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Col Running\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flag Running\"\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Flag Running\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 4 Color\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 2 Color\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow\"\n        },\n        {\n          \"dmxRange\": [126, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [134, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor\"\n        },\n        {\n          \"dmxRange\": [142, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 2\"\n        },\n        {\n          \"dmxRange\": [150, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 4\"\n        },\n        {\n          \"dmxRange\": [172, 255],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"What happens when this capability is selected?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\"\n      }\n    },\n    \"Program Direction\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Forward with Loop\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Forward one time and stop\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Reverse one time and stop\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Reverse with Loop\"\n        }\n      ]\n    },\n    \"Program Group Size\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 group\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 groups\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 groups\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 groups\"\n        }\n      ]\n    },\n    \"Group Offset\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\",\n        \"comment\": \"Offset\"\n      }\n    },\n    \"Restart Program\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Change value to restart program\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: RGB\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"2: RGBW\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"3: RGBAW\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"4: Dim RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"5: Dim RGBW\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"6: Dim RGBAW\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\"\n      ]\n    },\n    {\n      \"name\": \"7: RGB CCT Dim Ind\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Temperature Master\",\n        \"Dimmer Master\",\n        \"LEE Color Gel Master\"\n      ]\n    },\n    {\n      \"name\": \"8: RGBS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"9: RGBWS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"10: RGBAWS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"11: Dim RGBS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"12: Dim RGBWS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"13: Dim RGBAWS\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Emulated White Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"14: RGB CCT Dim Ind S\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Temperature Master\",\n        \"Dimmer Master\",\n        \"LEE Color Gel Master\",\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"15: Effect Fix\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe Master\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade Time\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Group Offset\",\n        \"Restart Program\",\n        \"LEE Color Gel Effect Color 1\",\n        \"LEE Color Gel Effect Color 2\",\n        \"LEE Color Gel Effect Color 3\",\n        \"LEE Color Gel Effect Color 4\"\n      ]\n    },\n    {\n      \"name\": \"16: Effect RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe Master\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade Time\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Group Offset\",\n        \"Restart Program\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Effect Color 1\", \"Effect Color 2\", \"Effect Color 3\", \"Effect Color 4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"17: RGB.RGB. 8pix\",\n      \"channels\": [\n        \"Red 1/8\",\n        \"Green 1/8\",\n        \"Blue 1/8\",\n        null,\n        \"Red 2/8\",\n        \"Green 2/8\",\n        \"Blue 2/8\",\n        null,\n        \"Red 3/8\",\n        \"Green 3/8\",\n        \"Blue 3/8\",\n        null,\n        \"Red 4/8\",\n        \"Green 4/8\",\n        \"Blue 4/8\",\n        null,\n        \"Red 5/8\",\n        \"Green 5/8\",\n        \"Blue 5/8\",\n        null,\n        \"Red 6/8\",\n        \"Green 6/8\",\n        \"Blue 6/8\",\n        null,\n        \"Red 7/8\",\n        \"Green 7/8\",\n        \"Blue 7/8\",\n        null,\n        \"Red 8/8\",\n        \"Green 8/8\",\n        \"Blue 8/8\"\n      ]\n    },\n    {\n      \"name\": \"18: RGB RGB 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"19: RGBW RGBW 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"20: RGBAW RGBAW 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"21: Dim RGB Dim RGB 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"22: Dim RGBW Dim RGBW 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"23: Dim RGBAW Dim RGBAW 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"24: RGB CCT Dim Ind 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"25: RGB.RGBS 8pix\",\n      \"channels\": [\n        \"Red 1/8\",\n        \"Green 1/8\",\n        \"Blue 1/8\",\n        \"Strobe Master\",\n        \"Red 2/8\",\n        \"Green 2/8\",\n        \"Blue 2/8\",\n        null,\n        \"Red 3/8\",\n        \"Green 3/8\",\n        \"Blue 3/8\",\n        null,\n        \"Red 4/8\",\n        \"Green 4/8\",\n        \"Blue 4/8\",\n        null,\n        \"Red 5/8\",\n        \"Green 5/8\",\n        \"Blue 5/8\",\n        null,\n        \"Red 6/8\",\n        \"Green 6/8\",\n        \"Blue 6/8\",\n        null,\n        \"Red 7/8\",\n        \"Green 7/8\",\n        \"Blue 7/8\",\n        null,\n        \"Red 8/8\",\n        \"Green 8/8\",\n        \"Blue 8/8\"\n      ]\n    },\n    {\n      \"name\": \"26: RGB RGB .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"27: RGBW RGBW .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"28: RGBAW RGBAW .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"29: Dim RGB Dim RGB .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"30: Dim RGBW Dim RGBW .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"31: Dim RGBAW Dim RGBAW .. S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"32: RGB CCT Dim Ind S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"33: RGBSRGBS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"34: RGB RGB .. SS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"35: RGBWS RGBWS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"36: RGBAWS RGBAWS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"37: Dim RGBS Dim RGBS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"38: Dim RGBWS Dim RGBWS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"39: Dim RGBAWS Dim RGBAWS 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"40: RGB CCT Dim Ind S 8pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"41: RGB.RGB. 32pix\",\n      \"channels\": [\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        null,\n        \"Red 2\",\n        \"Green 2\",\n        \"Blue 2\",\n        null,\n        \"Red 3\",\n        \"Green 3\",\n        \"Blue 3\",\n        null,\n        \"Red 4\",\n        \"Green 4\",\n        \"Blue 4\",\n        null,\n        \"Red 5\",\n        \"Green 5\",\n        \"Blue 5\",\n        null,\n        \"Red 6\",\n        \"Green 6\",\n        \"Blue 6\",\n        null,\n        \"Red 7\",\n        \"Green 7\",\n        \"Blue 7\",\n        null,\n        \"Red 8\",\n        \"Green 8\",\n        \"Blue 8\",\n        null,\n        \"Red 9\",\n        \"Green 9\",\n        \"Blue 9\",\n        null,\n        \"Red 10\",\n        \"Green 10\",\n        \"Blue 10\",\n        null,\n        \"Red 11\",\n        \"Green 11\",\n        \"Blue 11\",\n        null,\n        \"Red 12\",\n        \"Green 12\",\n        \"Blue 12\",\n        null,\n        \"Red 13\",\n        \"Green 13\",\n        \"Blue 13\",\n        null,\n        \"Red 14\",\n        \"Green 14\",\n        \"Blue 14\",\n        null,\n        \"Red 15\",\n        \"Green 15\",\n        \"Blue 15\",\n        null,\n        \"Red 16\",\n        \"Green 16\",\n        \"Blue 16\",\n        null,\n        \"Red 17\",\n        \"Green 17\",\n        \"Blue 17\",\n        null,\n        \"Red 18\",\n        \"Green 18\",\n        \"Blue 18\",\n        null,\n        \"Red 19\",\n        \"Green 19\",\n        \"Blue 19\",\n        null,\n        \"Red 20\",\n        \"Green 20\",\n        \"Blue 20\",\n        null,\n        \"Red 21\",\n        \"Green 21\",\n        \"Blue 21\",\n        null,\n        \"Red 22\",\n        \"Green 22\",\n        \"Blue 22\",\n        null,\n        \"Red 23\",\n        \"Green 23\",\n        \"Blue 23\",\n        null,\n        \"Red 24\",\n        \"Green 24\",\n        \"Blue 24\",\n        null,\n        \"Red 25\",\n        \"Green 25\",\n        \"Blue 25\",\n        null,\n        \"Red 26\",\n        \"Green 26\",\n        \"Blue 26\",\n        null,\n        \"Red 27\",\n        \"Green 27\",\n        \"Blue 27\",\n        null,\n        \"Red 28\",\n        \"Green 28\",\n        \"Blue 28\",\n        null,\n        \"Red 29\",\n        \"Green 29\",\n        \"Blue 29\",\n        null,\n        \"Red 30\",\n        \"Green 30\",\n        \"Blue 30\",\n        null,\n        \"Red 31\",\n        \"Green 31\",\n        \"Blue 31\",\n        null,\n        \"Red 32\",\n        \"Green 32\",\n        \"Blue 32\"\n      ]\n    },\n    {\n      \"name\": \"42: RGB RGB 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"43: RGBW RGBW 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"44: RGBAW RGBAW 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"45: Dim RGB Dim RGB 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"46: Dim RGBW Dim RGBW 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"47: Dim RGBAW Dim RGBAW 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"48: RGB CCT Dim Ind 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"49: RGB.RGBS 32pix\",\n      \"channels\": [\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        \"Strobe Master\",\n        \"Red 2\",\n        \"Green 2\",\n        \"Blue 2\",\n        null,\n        \"Red 3\",\n        \"Green 3\",\n        \"Blue 3\",\n        null,\n        \"Red 4\",\n        \"Green 4\",\n        \"Blue 4\",\n        null,\n        \"Red 5\",\n        \"Green 5\",\n        \"Blue 5\",\n        null,\n        \"Red 6\",\n        \"Green 6\",\n        \"Blue 6\",\n        null,\n        \"Red 7\",\n        \"Green 7\",\n        \"Blue 7\",\n        null,\n        \"Red 8\",\n        \"Green 8\",\n        \"Blue 8\",\n        null,\n        \"Red 9\",\n        \"Green 9\",\n        \"Blue 9\",\n        null,\n        \"Red 10\",\n        \"Green 10\",\n        \"Blue 10\",\n        null,\n        \"Red 11\",\n        \"Green 11\",\n        \"Blue 11\",\n        null,\n        \"Red 12\",\n        \"Green 12\",\n        \"Blue 12\",\n        null,\n        \"Red 13\",\n        \"Green 13\",\n        \"Blue 13\",\n        null,\n        \"Red 14\",\n        \"Green 14\",\n        \"Blue 14\",\n        null,\n        \"Red 15\",\n        \"Green 15\",\n        \"Blue 15\",\n        null,\n        \"Red 16\",\n        \"Green 16\",\n        \"Blue 16\",\n        null,\n        \"Red 17\",\n        \"Green 17\",\n        \"Blue 17\",\n        null,\n        \"Red 18\",\n        \"Green 18\",\n        \"Blue 18\",\n        null,\n        \"Red 19\",\n        \"Green 19\",\n        \"Blue 19\",\n        null,\n        \"Red 20\",\n        \"Green 20\",\n        \"Blue 20\",\n        null,\n        \"Red 21\",\n        \"Green 21\",\n        \"Blue 21\",\n        null,\n        \"Red 22\",\n        \"Green 22\",\n        \"Blue 22\",\n        null,\n        \"Red 23\",\n        \"Green 23\",\n        \"Blue 23\",\n        null,\n        \"Red 24\",\n        \"Green 24\",\n        \"Blue 24\",\n        null,\n        \"Red 25\",\n        \"Green 25\",\n        \"Blue 25\",\n        null,\n        \"Red 26\",\n        \"Green 26\",\n        \"Blue 26\",\n        null,\n        \"Red 27\",\n        \"Green 27\",\n        \"Blue 27\",\n        null,\n        \"Red 28\",\n        \"Green 28\",\n        \"Blue 28\",\n        null,\n        \"Red 29\",\n        \"Green 29\",\n        \"Blue 29\",\n        null,\n        \"Red 30\",\n        \"Green 30\",\n        \"Blue 30\",\n        null,\n        \"Red 31\",\n        \"Green 31\",\n        \"Blue 31\",\n        null,\n        \"Red 32\",\n        \"Green 32\",\n        \"Blue 32\"\n      ]\n    },\n    {\n      \"name\": \"50: RGB RGB .. S 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"51: RGBW RGBW .. S 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"52: RGBAW RGBAW .. S 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"53: Dim RGB Dim RGB .. S 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"54: Dim RGBW Dim RGBW .. S 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"55: Dim RGBAW Dim RGBAW .. S 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"56: RGB CCT Dim Ind S 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\"\n          ]\n        },\n        \"Strobe Master\"\n      ]\n    },\n    {\n      \"name\": \"57: RGBSRGBS 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"58: RGB RGB .. SS 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"59: RGBWS RGBWS 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"60: RGBAWS RGBAWS 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"61: Dim RGBS Dim RGBS 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"62: Dim RGBWS Dim RGBWS 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"63: Dim RGBAWS Dim RGBAWS 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Emulated White $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"64: RGB CCT Dim Ind S 32pix\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Color Temperature $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"LEE Color Gel $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"89: D CCT GM CRO RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Crossfade Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"90: D CCT GM HUE SAT\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Hue Master\",\n        \"Saturation Master\"\n      ]\n    },\n    {\n      \"name\": \"91: D16 CCT GM CRO RGB\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Dimmer Master fine\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Crossfade Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"92: D16 CCT GM H SAT\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Dimmer Master fine\",\n        \"CCT Master\",\n        \"Green-Magenta Point Master\",\n        \"Hue Master\",\n        \"Hue Master fine\",\n        \"Saturation Master\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/astera/fp5-nyx-bulb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"FP5 NYX Bulb\",\n  \"shortName\": \"AsteraFP5NYX\",\n  \"categories\": [\"Color Changer\", \"Blinder\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jack Crombie\", \"Felix Edelmann\", \"Dyami Caliri\"],\n    \"createDate\": \"2021-01-12\",\n    \"lastModifyDate\": \"2021-01-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://astera-led.com/Downloads/Profile/NYX%20Bulb%20DMX%20Profiles.pdf\"\n    ],\n    \"productPage\": [\n      \"https://astera-led.com/products/nyx-bulb/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=CiSduB4M5RU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [130, 70, 70],\n    \"weight\": 0.24,\n    \"power\": 10,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 750\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [ \"Master\", \"Effect Color 1\", \"Effect Color 2\", \"Effect Color 3\", \"Effect Color 4\" ]\n      ]\n    ]\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"LEE Color Gel $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\",\n          \"colors\": [\"#ff8fb9\"]\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\",\n          \"colors\": [\"#ffdab5\"]\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Bastard Amber\",\n          \"colors\": [\"#ffb783\"]\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\",\n          \"colors\": [\"#ffd78c\"]\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\",\n          \"colors\": [\"#ff814c\"]\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\",\n          \"colors\": [\"#ffc176\"]\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\",\n          \"colors\": [\"#ffd21c\"]\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\",\n          \"colors\": [\"#ffc069\"]\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\",\n          \"colors\": [\"#ff9f00\"]\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\",\n          \"colors\": [\"#ffa25b\"]\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\",\n          \"colors\": [\"#ff391b\"]\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\",\n          \"colors\": [\"#ff9123\"]\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\",\n          \"colors\": [\"#ff7600\"]\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\",\n          \"colors\": [\"#ff4f0a\"]\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\",\n          \"colors\": [\"#ff5647\"]\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\",\n          \"colors\": [\"#ff6f2f\"]\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\",\n          \"colors\": [\"#ff0012\"]\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\",\n          \"colors\": [\"#ff0020\"]\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Plasa Red\",\n          \"colors\": [\"#ff2707\"]\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#ffbaa1\"]\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\",\n          \"colors\": [\"#ff9f98\"]\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\",\n          \"colors\": [\"#ff0055\"]\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\",\n          \"colors\": [\"#ff95e0\"]\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Purple\",\n          \"colors\": [\"#ff50f1\"]\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\",\n          \"colors\": [\"#ffdcf6\"]\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\",\n          \"colors\": [\"#ffe5ca\"]\n        },\n        {\n          \"dmxRange\": [54, 57],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#af7cff\"]\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\",\n          \"colors\": [\"#fff9db\"]\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\",\n          \"colors\": [\"#f6ffeb\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#00acff\"]\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tokyo Blue\",\n          \"colors\": [\"#0040ff\"]\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Evening Blue\",\n          \"colors\": [\"#00a1ff\"]\n        },\n        {\n          \"dmxRange\": [76, 78],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\",\n          \"colors\": [\"#007bff\"]\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\",\n          \"colors\": [\"#0075ff\"]\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\",\n          \"colors\": [\"#fffe4c\"]\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\",\n          \"colors\": [\"#a7ff58\"]\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Yellow Green\",\n          \"colors\": [\"#3aff42\"]\n        },\n        {\n          \"dmxRange\": [91, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\",\n          \"colors\": [\"#ffd930\"]\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffc600\"]\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\",\n          \"colors\": [\"#ffba45\"]\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\",\n          \"colors\": [\"#ffd88f\"]\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\",\n          \"colors\": [\"#ffa704\"]\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8700\"]\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\",\n          \"colors\": [\"#ff0018\"]\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\",\n          \"colors\": [\"#ff8d7e\"]\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\",\n          \"colors\": [\"#ffa76b\"]\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\",\n          \"colors\": [\"#ff9a83\"]\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\",\n          \"colors\": [\"#ff9ba1\"]\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\",\n          \"colors\": [\"#ff7194\"]\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff0059\"]\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\",\n          \"colors\": [\"#00ffd8\"]\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue-Green\",\n          \"colors\": [\"#00ffe1\"]\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\",\n          \"colors\": [\"#ffc8de\"]\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\",\n          \"colors\": [\"#0069ff\"]\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\",\n          \"colors\": [\"#0062ff\"]\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Green\",\n          \"colors\": [\"#cfff53\"]\n        },\n        {\n          \"dmxRange\": [122, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\",\n          \"colors\": [\"#8fff60\"]\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\",\n          \"colors\": [\"#00ff66\"]\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#ff00f1\"]\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\",\n          \"colors\": [\"#ff8987\"]\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\",\n          \"colors\": [\"#ff2e9b\"]\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Heavy Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Clear\",\n          \"colors\": [\"#ffb258\"]\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\",\n          \"colors\": [\"#8fffd3\"]\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [133, 133],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\",\n          \"colors\": [\"#ff8944\"]\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Golden Amber\",\n          \"colors\": [\"#ff4200\"]\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\",\n          \"colors\": [\"#ffd0cd\"]\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\",\n          \"colors\": [\"#d6c1ff\"]\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\",\n          \"colors\": [\"#fff87c\"]\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\",\n          \"colors\": [\"#4bff00\"]\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\",\n          \"colors\": [\"#a8fffc\"]\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\",\n          \"colors\": [\"#00c8ff\"]\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\",\n          \"colors\": [\"#afaeff\"]\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\",\n          \"colors\": [\"#50e5ff\"]\n        },\n        {\n          \"dmxRange\": [144, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Blue\",\n          \"colors\": [\"#7df5ff\"]\n        },\n        {\n          \"dmxRange\": [145, 146],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\",\n          \"colors\": [\"#ffa255\"]\n        },\n        {\n          \"dmxRange\": [148, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\",\n          \"colors\": [\"#ff536c\"]\n        },\n        {\n          \"dmxRange\": [149, 150],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\",\n          \"colors\": [\"#ffb78b\"]\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\",\n          \"colors\": [\"#ffb684\"]\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\",\n          \"colors\": [\"#ffae8f\"]\n        },\n        {\n          \"dmxRange\": [154, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\",\n          \"colors\": [\"#ffbd92\"]\n        },\n        {\n          \"dmxRange\": [155, 155],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\",\n          \"colors\": [\"#ffbc77\"]\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff716e\"]\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\",\n          \"colors\": [\"#ff7800\"]\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Colour Straw\",\n          \"colors\": [\"#ffd79c\"]\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\",\n          \"colors\": [\"#67cdff\"]\n        },\n        {\n          \"dmxRange\": [162, 162],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\",\n          \"colors\": [\"#ffc290\"]\n        },\n        {\n          \"dmxRange\": [163, 163],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\",\n          \"colors\": [\"#ff3622\"]\n        },\n        {\n          \"dmxRange\": [165, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\",\n          \"colors\": [\"#00c2ff\"]\n        },\n        {\n          \"dmxRange\": [166, 168],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\",\n          \"colors\": [\"#ffd9c1\"]\n        },\n        {\n          \"dmxRange\": [170, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\",\n          \"colors\": [\"#ffc0e1\"]\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [172, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\",\n          \"colors\": [\"#00f3ff\"]\n        },\n        {\n          \"dmxRange\": [173, 173],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\",\n          \"colors\": [\"#abe0ff\"]\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [176, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\",\n          \"colors\": [\"#ff9d75\"]\n        },\n        {\n          \"dmxRange\": [177, 178],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\",\n          \"colors\": [\"#ff9e00\"]\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\",\n          \"colors\": [\"#8866ff\"]\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\",\n          \"colors\": [\"#1a44ff\"]\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff3914\"]\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\",\n          \"colors\": [\"#00cfff\"]\n        },\n        {\n          \"dmxRange\": [184, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\",\n          \"colors\": [\"#ffd19c\"]\n        },\n        {\n          \"dmxRange\": [185, 185],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Rose\",\n          \"colors\": [\"#ffcca5\"]\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Rouge\",\n          \"colors\": [\"#ffcb97\"]\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Highlight\",\n          \"colors\": [\"#ffcf9b\"]\n        },\n        {\n          \"dmxRange\": [189, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Silver Moss\",\n          \"colors\": [\"#ffda98\"]\n        },\n        {\n          \"dmxRange\": [190, 190],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Aqua Blue\",\n          \"colors\": [\"#ffe5b3\"]\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\",\n          \"colors\": [\"#ff7487\"]\n        },\n        {\n          \"dmxRange\": [193, 193],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\",\n          \"colors\": [\"#e5c7ff\"]\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\",\n          \"colors\": [\"#005fff\"]\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\",\n          \"colors\": [\"#64deff\"]\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\",\n          \"colors\": [\"#3aa0ff\"]\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\",\n          \"colors\": [\"#00d2ff\"]\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Regal Blue\",\n          \"colors\": [\"#2d72ff\"]\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Double CT Blue\",\n          \"colors\": [\"#6fbcff\"]\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Blue\",\n          \"colors\": [\"#dbf5ff\"]\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Blue\",\n          \"colors\": [\"#fffce6\"]\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Blue\",\n          \"colors\": [\"#ffe9c7\"]\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange\",\n          \"colors\": [\"#ffa955\"]\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 CT Orange\",\n          \"colors\": [\"#ffc079\"]\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 CT Orange\",\n          \"colors\": [\"#ffc98e\"]\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\",\n          \"colors\": [\"#ffa858\"]\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full CT Orange +\",\n          \"colors\": [\"#ffa853\"]\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.3 Neutral Density\",\n          \"colors\": [\"#ffdcab\"]\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.6 Neutral Density\",\n          \"colors\": [\"#ffddad\"]\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"0.9 Neutral Density\",\n          \"colors\": [\"#ffdeaa\"]\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LCT Yellow\",\n          \"colors\": [\"#ffd68c\"]\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Flame Green\",\n          \"colors\": [\"#ffe89c\"]\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Blue\",\n          \"colors\": [\"#ffe1b7\"]\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent Green\",\n          \"colors\": [\"#a9ffc1\"]\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emulated White Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [221, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [222, 222],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 CT Orange\",\n          \"colors\": [\"#ffd39b\"]\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE N.D. Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [226, 226],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE U.V.\",\n          \"colors\": [\"#ffdaa8\"]\n        },\n        {\n          \"dmxRange\": [227, 227],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brushed Silk\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Tough Spun\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [230, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Correction\",\n          \"colors\": [\"#ffc67c\"]\n        },\n        {\n          \"dmxRange\": [231, 231],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [232, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Super Emulated White Flame Green\",\n          \"colors\": [\"#ffad5d\"]\n        },\n        {\n          \"dmxRange\": [233, 235],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"H.M.I (To Tungsten)\",\n          \"colors\": [\"#ffa95f\"]\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.I.D. (To Tungsten)\",\n          \"colors\": [\"#ffa360\"]\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"C.S.I. (To Tungsten)\",\n          \"colors\": [\"#ffb483\"]\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Polariser\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 5700 K\",\n          \"colors\": [\"#ccffdc\"]\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 4300 K\",\n          \"colors\": [\"#e0ffb8\"]\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Fluorescent 3600 K\",\n          \"colors\": [\"#f2ffa8\"]\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Plus Green\",\n          \"colors\": [\"#ffed8f\"]\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Plus Green\",\n          \"colors\": [\"#ffe49b\"]\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Plus Green\",\n          \"colors\": [\"#ffe0a3\"]\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE Minus Green\",\n          \"colors\": [\"#ffbdaa\"]\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Minus Green\",\n          \"colors\": [\"#ffccab\"]\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Minus Green\",\n          \"colors\": [\"#ffd5ad\"]\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/2 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/4 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"1/8 Emulated White Diffusion\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hampshire Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"New Hampshire Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Frost\",\n          \"helpWanted\": \"What is the RGB color mixing?\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Emulated White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2100K\",\n          \"colorTemperatureEnd\": \"7100K\",\n          \"helpWanted\": \"Does this capability already begin at DMX value 4 (with 2080K)?\"\n        }\n      ]\n    },\n    \"CCT\": {\n      \"capability\":\n        {\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1750K\",\n          \"colorTemperatureEnd\": \"9910K\"\n        }\n    },\n    \"Crossfade\": {\n      \"capability\":\n        {\n          \"type\": \"Generic\",\n          \"comment\": \"CCT crossfade to RGB\"\n        }\n    },\n    \"Green-Magenta Point\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…100%\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [7, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.4Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Static\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Static\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Static\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Static\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"One Color Fade\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Color Fade\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three Color Fade\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Four Color Fade\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Simple Running\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Running\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Two Col Running\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flag Running\"\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Flag Running\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 4 Color\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral 2 Color\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow\"\n        },\n        {\n          \"dmxRange\": [126, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [134, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor\"\n        },\n        {\n          \"dmxRange\": [142, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 2\"\n        },\n        {\n          \"dmxRange\": [150, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotor Split 4\"\n        },\n        {\n          \"dmxRange\": [172, 255],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"What happens when this capability is selected?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Fade Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\"\n      }\n    },\n    \"Program Direction\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Forward with Loop\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Forward one time and stop\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Reverse one time and stop\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Reverse with Loop\"\n        }\n      ]\n    },\n    \"Program Group Size\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 group\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 groups\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 groups\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 groups\"\n        }\n      ]\n    },\n    \"Group Offset\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\",\n        \"comment\": \"Offset\"\n      }\n    },\n    \"Restart Program\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Change value to restart program\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: RGB\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"2: RGBW\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White\"\n      ]\n    },\n    {\n      \"name\": \"3: RGBAW\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber\",\n        \"Emulated White\"\n      ]\n    },\n    {\n      \"name\": \"4: Dim RGB\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"5: Dim RGBW\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White\"\n      ]\n    },\n    {\n      \"name\": \"6: Dim RGBAW\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber\",\n        \"Emulated White\"\n      ]\n    },\n    {\n      \"name\": \"7: RGB CCT Dim Ind\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Temperature\",\n        \"Dimmer\",\n        \"LEE Color Gel Master\"\n      ]\n    },\n    {\n      \"name\": \"8: RGBS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"9: RGBWS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"10: RGBAWS\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber\",\n        \"Emulated White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11: Dim RGBS\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12: Dim RGBWS\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Emulated White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"13: Dim RGBAWS\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber\",\n        \"Emulated White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"14: RGB CCT Dim Ind S\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Temperature\",\n        \"Dimmer\",\n        \"LEE Color Gel Master\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"15: Effect Fix\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade Time\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Group Offset\",\n        \"Restart Program\",\n        \"LEE Color Gel Effect Color 1\",\n        \"LEE Color Gel Effect Color 2\",\n        \"LEE Color Gel Effect Color 3\",\n        \"LEE Color Gel Effect Color 4\"\n      ]\n    },\n    {\n      \"name\": \"16: Effect RGB\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Program Fade Time\",\n        \"Program Direction\",\n        \"Program Group Size\",\n        \"Group Offset\",\n        \"Restart Program\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Effect Color 1\", \"Effect Color 2\", \"Effect Color 3\", \"Effect Color 4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"89: D CCT GM CRO RGB\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"90: D CCT GM HUE SAT\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"Green-Magenta Point\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"91: D16 CCT GM CRO RGB\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"92: D16 CCT GM H SAT\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"Green-Magenta Point\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/audibax/boston-60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Boston 60\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Saúl\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-12-12\",\n    \"lastModifyDate\": \"2020-12-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.madridhifi.com/crm/documents/produit/9/4/10157449/photos/pdf/1/Boston%2060.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [155, 235, 145],\n    \"weight\": 3.5,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"60W White LED\"\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"0%\",\n      \"constant\": true,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 8,\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 8,\n          \"helpWanted\": \"Which gobos can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Strobe Speed\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"1Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode 3\"\n        },\n        {\n          \"dmxRange\": [85, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode 2\"\n        },\n        {\n          \"dmxRange\": [110, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode 1\"\n        },\n        {\n          \"dmxRange\": [135, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode 0\"\n        },\n        {\n          \"dmxRange\": [160, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [185, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [210, 234],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [235, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 0\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Strobe Speed\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Auto Programs\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Strobe Speed\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Auto Programs\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ayra/compar-20.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Compar 20\",\n  \"categories\": [\"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Ljrens vd Burgt\", \"Ken Harris\", \"Flo Edelmann\"],\n    \"createDate\": \"2024-03-05\",\n    \"lastModifyDate\": \"2024-03-05\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.bax-shop.nl/index3.php?option=com_download_files&product_id=74745&download_id=1571\"\n    ],\n    \"productPage\": [\n      \"https://www.bax-shop.nl/led-compact-par/ayra-compar-20-rgb-led-spot\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ekqFm7sORMQ\"\n    ]\n  },\n  \"physical\": {\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\",\n          \"helpWanted\": \"Is DMX value 147 yellow or magenta?\"\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1…15\",\n          \"helpWanted\": \"What colors at what values?\"\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Effect\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ayra/tdc-triple-burst.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"TDC Triple Burst\",\n  \"shortName\": \"AyraTDCTripleBurst\",\n  \"categories\": [\"Color Changer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-12-14\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.bax-shop.nl/downloads/products/9000-0007-6647/ayra_tdc_triple_burst_manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.bax-shop.co.uk/led-light-effect/ayra-tdc-triple-burst-led-lichteffect\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=WKCW9-JtCfs\",\n      \"https://www.youtube.com/watch?v=Xt2d_Y9eGzs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [375, 260, 100],\n    \"weight\": 3,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"15x 3W LED (R/G/B/W/A)\"\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [3, 1, 1]\n  },\n  \"availableChannels\": {\n    \"Show\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 1\"\n        },\n        {\n          \"dmxRange\": [38, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 2\"\n        },\n        {\n          \"dmxRange\": [68, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 3\"\n        },\n        {\n          \"dmxRange\": [98, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 4\"\n        },\n        {\n          \"dmxRange\": [128, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 5\"\n        },\n        {\n          \"dmxRange\": [158, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 6\"\n        },\n        {\n          \"dmxRange\": [188, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 7\"\n        },\n        {\n          \"dmxRange\": [218, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 8\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Show 1 - 8\"\n        }\n      ]\n    },\n    \"Color chase\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual control\"\n        },\n        {\n          \"dmxRange\": [8, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 1\"\n        },\n        {\n          \"dmxRange\": [23, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 2\"\n        },\n        {\n          \"dmxRange\": [38, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 3\"\n        },\n        {\n          \"dmxRange\": [53, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 4\"\n        },\n        {\n          \"dmxRange\": [68, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 5\"\n        },\n        {\n          \"dmxRange\": [83, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 6\"\n        },\n        {\n          \"dmxRange\": [98, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 7\"\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 8\"\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 9\"\n        },\n        {\n          \"dmxRange\": [143, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 10\"\n        },\n        {\n          \"dmxRange\": [158, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 11\"\n        },\n        {\n          \"dmxRange\": [173, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 12\"\n        },\n        {\n          \"dmxRange\": [188, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 13\"\n        },\n        {\n          \"dmxRange\": [203, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 14\"\n        },\n        {\n          \"dmxRange\": [218, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 15\"\n        },\n        {\n          \"dmxRange\": [233, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color chase 16\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Stand alone show\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1 channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\"Show\"]\n    },\n    {\n      \"name\": \"3 channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\"Color chase\", \"Dimmer\", \"Strobe\"]\n    },\n    {\n      \"name\": \"9 channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color chase\",\n        \"Speed\"\n      ]\n    },\n    {\n      \"name\": \"15 channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"19 channel\",\n      \"shortName\": \"19ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        },\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color chase\",\n        \"Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ayrton/diablo-s.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Diablo-S\",\n  \"shortName\": \"AyrtonDiabloS\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-24\",\n    \"lastModifyDate\": \"2019-07-24\"\n  },\n  \"comment\": \"Productcode 011340\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.ayrton.eu/wp-content/uploads/2018/12/Diablo-V1.pdf\",\n      \"https://www.ayrton.eu/wp-content/uploads/2018/12/Diablo-color-wheel-1-1.pdf\",\n      \"https://www.ayrton.eu/wp-content/uploads/2018/12/Diablo-Gobos.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.ayrton.eu/produit/diablo/\"\n    ],\n    \"video\": [\n      \"https://vimeo.com/310056757\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [364.9, 591.6, 210.6],\n    \"weight\": 21.8,\n    \"power\": 550,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"White LED\",\n      \"colorTemperature\": 6500,\n      \"lumens\": 17500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [6.7, 53]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB\",\n          \"colors\": [\"#7db0db\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#a3639c\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Congo Blue\",\n          \"colors\": [\"#1a3885\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00a13b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#e87817\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0091fa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"AnimationGoboStart\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by movement\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by all wheel changing\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 11,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [21, 117],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [118, 126],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [127, 180],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [181, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 245],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Chase Pattern\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [50, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Chase Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 125],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [131, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Chase Fade\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Auto Focus\": {\n      \"fineChannelAliases\": [\"Auto Focus fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Focus\",\n          \"distance\": \"5m\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Focus\",\n          \"distance\": \"7.5m\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Focus\",\n          \"distance\": \"10m\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Focus\",\n          \"distance\": \"15m\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 127],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"fineChannelAliases\": [\"Magenta fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"fineChannelAliases\": [\"Yellow fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"fineChannelAliases\": [\"CTO fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"default\",\n        \"colorTemperatureEnd\": \"CTO\"\n      }\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [78, 93],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [94, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 141],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [142, 157],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [158, 173],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [174, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [190, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [136, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"fineChannelAliases\": [\"Iris fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"100%\",\n          \"openPercentEnd\": \"15%\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse closing\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse opening\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"5-facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"fineChannelAliases\": [\"Prism Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Blade 1A Insertion\": {\n      \"fineChannelAliases\": [\"Blade 1A Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 1B Insertion\": {\n      \"fineChannelAliases\": [\"Blade 1B Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 2A Insertion\": {\n      \"fineChannelAliases\": [\"Blade 2A Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 2B Insertion\": {\n      \"fineChannelAliases\": [\"Blade 2B Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 3A Insertion\": {\n      \"fineChannelAliases\": [\"Blade 3A Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 3,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 3B Insertion\": {\n      \"fineChannelAliases\": [\"Blade 3B Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 3,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 4A Insertion\": {\n      \"fineChannelAliases\": [\"Blade 4A Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 4,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frost\": {\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Blade 4B Insertion\": {\n      \"fineChannelAliases\": [\"Blade 4B Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 4,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade System Rotation\": {\n      \"fineChannelAliases\": [\"Blade System Rotation fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"BladeSystemRotation\",\n        \"angleStart\": \"-45deg\",\n        \"angleEnd\": \"45deg\"\n      }\n    },\n    \"Maintenance / Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Off\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display On\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Invert Off\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Invert On\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Auto fan control mode\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage fan control mode\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Studio fan control mode\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silence fan control mode\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square Law\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"1.2K\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"2.4K\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16K\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo correction Off\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo correction On\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motor reset\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Scan motor reset\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colors motor reset\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo motor reset\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Other motor reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1 (Scene 1…8 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 2 (Scene 9…16 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 3 (Scene 17…24 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 4 (Scene 25…32 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 5 (Scene 33…40 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 6 (Scene 41…48 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 7 (Scene 49…56 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 8 (Scene 57…64 of EEPROM)\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Chase Pattern\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Focus\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Animation Wheel\",\n        \"Iris\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Blade 1A Insertion\",\n        \"Blade 1B Insertion\",\n        \"Blade 2A Insertion\",\n        \"Blade 2B Insertion\",\n        \"Blade 3A Insertion\",\n        \"Blade 3B Insertion\",\n        \"Blade 4A Insertion\",\n        \"Blade 4B Insertion\",\n        \"Blade System Rotation\",\n        \"Maintenance / Programs\"\n      ]\n    },\n    {\n      \"name\": \"Basic\",\n      \"shortName\": \"bas\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Chase Pattern\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Focus\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Animation Wheel\",\n        \"Iris\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Blade 1A Insertion\",\n        \"Blade 1B Insertion\",\n        \"Blade 2A Insertion\",\n        \"Blade 2B Insertion\",\n        \"Blade 3A Insertion\",\n        \"Blade 3B Insertion\",\n        \"Blade 4A Insertion\",\n        \"Blade 4B Insertion\",\n        \"Blade System Rotation\",\n        \"Maintenance / Programs\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Chase Pattern\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\",\n        \"CTO\",\n        \"CTO fine\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Animation Wheel\",\n        \"Iris\",\n        \"Iris fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Prism Rotation fine\",\n        \"Frost\",\n        \"Blade 1A Insertion\",\n        \"Blade 1A Insertion fine\",\n        \"Blade 1B Insertion\",\n        \"Blade 1B Insertion fine\",\n        \"Blade 2A Insertion\",\n        \"Blade 2A Insertion fine\",\n        \"Blade 2B Insertion\",\n        \"Blade 2B Insertion fine\",\n        \"Blade 3A Insertion\",\n        \"Blade 3A Insertion fine\",\n        \"Blade 3B Insertion\",\n        \"Blade 3B Insertion fine\",\n        \"Blade 4A Insertion\",\n        \"Blade 4A Insertion fine\",\n        \"Blade 4B Insertion\",\n        \"Blade 4B Insertion fine\",\n        \"Blade System Rotation\",\n        \"Blade System Rotation fine\",\n        \"Maintenance / Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ayrton/diablo-tc.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Diablo-TC\",\n  \"shortName\": \"AyrtonDiabloTC\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-24\",\n    \"lastModifyDate\": \"2019-07-24\"\n  },\n  \"comment\": \"Productcode 011350\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.ayrton.eu/wp-content/uploads/2018/12/Diablo-V1.pdf\",\n      \"https://www.ayrton.eu/wp-content/uploads/2018/12/Diablo-color-wheel-1-1.pdf\",\n      \"https://www.ayrton.eu/wp-content/uploads/2018/12/Diablo-Gobos.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.ayrton.eu/produit/diablo/\"\n    ],\n    \"video\": [\n      \"https://vimeo.com/310056757\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [364.9, 591.6, 210.6],\n    \"weight\": 21.8,\n    \"power\": 550,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"White LED\",\n      \"colorTemperature\": 5700,\n      \"lumens\": 14000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [6.7, 53]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB\",\n          \"colors\": [\"#7db0db\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#a3639c\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Congo Blue\",\n          \"colors\": [\"#1a3885\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00a13b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#e87817\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0091fa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"AnimationGoboStart\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by movement\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by all wheel changing\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 11,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [21, 117],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [118, 126],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [127, 180],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [181, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 245],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Chase Pattern\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [50, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Chase Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 125],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [131, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Chase Fade\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Auto Focus\": {\n      \"fineChannelAliases\": [\"Auto Focus fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Focus\",\n          \"distance\": \"5m\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Focus\",\n          \"distance\": \"7.5m\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Focus\",\n          \"distance\": \"10m\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Focus\",\n          \"distance\": \"15m\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 127],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"fineChannelAliases\": [\"Magenta fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"fineChannelAliases\": [\"Yellow fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"fineChannelAliases\": [\"CTO fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"default\",\n        \"colorTemperatureEnd\": \"CTO\"\n      }\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [78, 93],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [94, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 141],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [142, 157],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [158, 173],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [174, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [190, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [136, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"fineChannelAliases\": [\"Iris fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"100%\",\n          \"openPercentEnd\": \"15%\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse closing\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse opening\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"5-facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"fineChannelAliases\": [\"Prism Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Blade 1A Insertion\": {\n      \"fineChannelAliases\": [\"Blade 1A Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 1B Insertion\": {\n      \"fineChannelAliases\": [\"Blade 1B Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 2A Insertion\": {\n      \"fineChannelAliases\": [\"Blade 2A Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 2B Insertion\": {\n      \"fineChannelAliases\": [\"Blade 2B Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 3A Insertion\": {\n      \"fineChannelAliases\": [\"Blade 3A Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 3,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 3B Insertion\": {\n      \"fineChannelAliases\": [\"Blade 3B Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 3,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade 4A Insertion\": {\n      \"fineChannelAliases\": [\"Blade 4A Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 4,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frost\": {\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Blade 4B Insertion\": {\n      \"fineChannelAliases\": [\"Blade 4B Insertion fine\"],\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 4,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Blade System Rotation\": {\n      \"fineChannelAliases\": [\"Blade System Rotation fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"BladeSystemRotation\",\n        \"angleStart\": \"-45deg\",\n        \"angleEnd\": \"45deg\"\n      }\n    },\n    \"Maintenance / Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Off\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display On\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Invert Off\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Invert On\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Auto fan control mode\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage fan control mode\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Studio fan control mode\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silence fan control mode\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square Law\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"1.2K\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"2.4K\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16K\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo correction Off\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo correction On\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motor reset\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Scan motor reset\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colors motor reset\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo motor reset\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Other motor reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1 (Scene 1…8 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 2 (Scene 9…16 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 3 (Scene 17…24 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 4 (Scene 25…32 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 5 (Scene 33…40 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 6 (Scene 41…48 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 7 (Scene 49…56 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 8 (Scene 57…64 of EEPROM)\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Chase Pattern\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Focus\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Animation Wheel\",\n        \"Iris\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Blade 1A Insertion\",\n        \"Blade 1B Insertion\",\n        \"Blade 2A Insertion\",\n        \"Blade 2B Insertion\",\n        \"Blade 3A Insertion\",\n        \"Blade 3B Insertion\",\n        \"Blade 4A Insertion\",\n        \"Blade 4B Insertion\",\n        \"Blade System Rotation\",\n        \"Maintenance / Programs\"\n      ]\n    },\n    {\n      \"name\": \"Basic\",\n      \"shortName\": \"bas\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Chase Pattern\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Focus\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Animation Wheel\",\n        \"Iris\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Blade 1A Insertion\",\n        \"Blade 1B Insertion\",\n        \"Blade 2A Insertion\",\n        \"Blade 2B Insertion\",\n        \"Blade 3A Insertion\",\n        \"Blade 3B Insertion\",\n        \"Blade 4A Insertion\",\n        \"Blade 4B Insertion\",\n        \"Blade System Rotation\",\n        \"Maintenance / Programs\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Chase Pattern\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\",\n        \"CTO\",\n        \"CTO fine\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Animation Wheel\",\n        \"Iris\",\n        \"Iris fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Prism Rotation fine\",\n        \"Frost\",\n        \"Blade 1A Insertion\",\n        \"Blade 1A Insertion fine\",\n        \"Blade 1B Insertion\",\n        \"Blade 1B Insertion fine\",\n        \"Blade 2A Insertion\",\n        \"Blade 2A Insertion fine\",\n        \"Blade 2B Insertion\",\n        \"Blade 2B Insertion fine\",\n        \"Blade 3A Insertion\",\n        \"Blade 3A Insertion fine\",\n        \"Blade 3B Insertion\",\n        \"Blade 3B Insertion fine\",\n        \"Blade 4A Insertion\",\n        \"Blade 4A Insertion fine\",\n        \"Blade 4B Insertion\",\n        \"Blade 4B Insertion fine\",\n        \"Blade System Rotation\",\n        \"Blade System Rotation fine\",\n        \"Maintenance / Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ayrton/magicblade-fx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MagicBlade FX\",\n  \"shortName\": \"AyrtonMBFX\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\", \"Moving Head\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-07-21\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\"https://www.ayrton.eu/wp-content/uploads/2015/10/MAGICBLADE-FX-Preliminary-Manual.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2L0d_DaIdSY\",\n      \"https://www.youtube.com/watch?v=O0_XDlSOvMQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [612, 312, 191],\n    \"weight\": 13,\n    \"power\": 400,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"RGBW LEDs\",\n      \"lumens\": 3800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [3.6, 53]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [64, 64, 0],\n      \"spacing\": [2.8, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [7, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"265deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by movement\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Pan Continuous\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Tilt Continuous\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"in sequences\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red -> Yellow\",\n          \"colorsStart\": [\n            \"#ff0000\"\n          ],\n          \"colorsEnd\": [\n            \"#ffff00\"\n          ]\n        },\n        {\n          \"dmxRange\": [40, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow -> Green\",\n          \"colorsStart\": [\n            \"#ffff00\"\n          ],\n          \"colorsEnd\": [\n            \"#00ff00\"\n          ]\n        },\n        {\n          \"dmxRange\": [72, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green -> Cyan\",\n          \"colorsStart\": [\n            \"#00ff00\"\n          ],\n          \"colorsEnd\": [\n            \"#00ffff\"\n          ]\n        },\n        {\n          \"dmxRange\": [104, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan -> Blue\",\n          \"colorsStart\": [\n            \"#00ffff\"\n          ],\n          \"colorsEnd\": [\n            \"#0000ff\"\n          ]\n        },\n        {\n          \"dmxRange\": [136, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue -> Magenta\",\n          \"colorsStart\": [\n            \"#0000ff\"\n          ],\n          \"colorsEnd\": [\n            \"#ff00ff\"\n          ]\n        },\n        {\n          \"dmxRange\": [168, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta -> Red\",\n          \"colorsStart\": [\n            \"#ff00ff\"\n          ],\n          \"colorsEnd\": [\n            \"#ff0000\"\n          ]\n        },\n        {\n          \"dmxRange\": [200, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red -> White\",\n          \"colorsStart\": [\n            \"#ff0000\"\n          ],\n          \"colorsEnd\": [\n            \"#ffffff\"\n          ]\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Salmon\",\n          \"colors\": [\"#ffaaaa\"]\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#aaffaa\"]\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\",\n          \"colors\": [\"#d6e5fc\"]\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\",\n          \"colors\": [\"#e4d96f\"]\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\",\n          \"colors\": [\"#ccbfff\"]\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff8adc\"]\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 1\",\n          \"helpWanted\": \"What color are these rainbow capabilities? Or are they color change effects?\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 2\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 3\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 4\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 5\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 6\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 7\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 8\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 9\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 10\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 11\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 12\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 13\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 14\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 15\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 16\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 17\"\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 18\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow 19\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Color Presets Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Chase Patterns\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"LED turn off\"\n        },\n        {\n          \"dmxRange\": [15, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [31, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [47, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [63, 78],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [79, 94],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 5\"\n        },\n        {\n          \"dmxRange\": [95, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 6\"\n        },\n        {\n          \"dmxRange\": [111, 126],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 7\"\n        },\n        {\n          \"dmxRange\": [127, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 8\"\n        },\n        {\n          \"dmxRange\": [143, 158],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 9\"\n        },\n        {\n          \"dmxRange\": [159, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 10\"\n        },\n        {\n          \"dmxRange\": [175, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 11\"\n        },\n        {\n          \"dmxRange\": [191, 206],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 12\"\n        },\n        {\n          \"dmxRange\": [207, 222],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 13\"\n        },\n        {\n          \"dmxRange\": [223, 238],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 14\"\n        },\n        {\n          \"dmxRange\": [239, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 15\"\n        }\n      ]\n    },\n    \"Chase Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 125],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [131, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Chase Fade\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\",\n        \"comment\": \"Chase Fade\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"3.6deg\",\n        \"angleEnd\": \"53deg\",\n        \"helpWanted\": \"The manual notes 15…60, is this correct?\"\n      }\n    },\n    \"Reset / Internal Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motor reset\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Scan motor reset\"\n        },\n        {\n          \"dmxRange\": [88, 96],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Other motors reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1 (scene 1-8 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 2 (scene 9-16 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 3 (scene 17-24 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 4 (scene 25-32 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 5 (scene 33-40 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 6 (scene 41-48 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 7 (scene 49-56 of EEPROM)\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Pan Continuous\",\n        \"Tilt Continuous\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Macro\",\n        \"Color Presets\",\n        \"Color Presets Dimmer\",\n        \"Chase Patterns\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Reset / Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"Basic\",\n      \"shortName\": \"bas\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Pan Continuous\",\n        \"Tilt Continuous\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Macro\",\n        \"Color Presets\",\n        \"Color Presets Dimmer\",\n        \"Chase Patterns\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Reset / Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Pan Continuous\",\n        \"Tilt Continuous\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Macro\",\n        \"Color Presets\",\n        \"Color Presets Dimmer\",\n        \"Chase Patterns\",\n        \"Chase Speed\",\n        \"Chase Fade\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Reset / Internal Programs\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/beamz/h2000-faze-machine.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"H2000 Faze Machine\",\n  \"categories\": [\"Hazer\", \"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"DMS\"],\n    \"createDate\": \"2019-02-21\",\n    \"lastModifyDate\": \"2019-02-21\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2019-02-21\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.10.5b)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.tronios.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2F160.512+Beamz+Fazer+H2000+V1.4.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.beamzlighting.com/product/h2000-faze-machine-with-dmx/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Fxl80HCGqjA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [185, 350, 360],\n    \"weight\": 6.8,\n    \"power\": 1700,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Smoke\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogOutputStart\": \"off\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Fan\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"80%\",\n        \"speedEnd\": \"100%\",\n        \"comment\": \"Fan Speed\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Smoke\",\n        \"Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/beamz/panther-7r.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Panther 7R\",\n  \"shortName\": \"panther-7r\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Matteo Piccina\"],\n    \"createDate\": \"2019-12-22\",\n    \"lastModifyDate\": \"2019-12-27\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.tronios.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2F150.470_Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.tronios.com/panther-7r-moving-head/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=H47-USm9oco\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [370, 470, 290],\n    \"weight\": 18.7,\n    \"power\": 380,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"MSD 7R 230W\",\n      \"colorTemperature\": 8000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [2.5, 2.5]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#80aaff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cream white\",\n          \"colors\": [\"#ffcfaa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light yellow\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cold white\",\n          \"colors\": [\"#c4e7ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aquamarine\",\n          \"colors\": [\"#000080\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Warm white\",\n          \"colors\": [\"#ffdec4\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"10%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"20%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"30%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"45%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"60%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"75%\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Lines\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"3-pointed star\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"4-pointed star\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Big bubbles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Snakes\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"12-pointed star\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Blob\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Many small bubbles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Few small bubbles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Line 1\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Line 2\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"265deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"13Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Auto\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto running\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is this slow…fast or fast…slow?\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [72, 113],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [114, 118],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [119, 160],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 16,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 17,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 18,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Are these the correct angles?\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is this the clockwise or counterclockwise? Is this slow…fast or fast…slow?\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 76],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [77, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt reset\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All reset\"\n        }\n      ]\n    },\n    \"Lamp\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\",\n          \"hold\": \"3s\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Auto\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Reset\",\n        \"Lamp\",\n        \"Frost\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/beamz/pls25-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PLS25 Par\",\n  \"categories\": [\"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Marek Jędrzejewski\"],\n    \"createDate\": \"2020-03-28\",\n    \"lastModifyDate\": \"2020-03-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.tronios.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2F153.252_153.255_153.258+PLS-Series+IRC+Batt+DMX+V1.1.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Kd83PELCiGo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [160, 115, 120],\n    \"weight\": 0.6,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 1W LEDs (3× red, 3× green, 3× blue, 3× white)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 10],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/beamz/triple-flex-centre-pro-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Triple Flex Centre Pro LED\",\n  \"categories\": [\"Flower\", \"Scanner\"],\n  \"meta\": {\n    \"authors\": [\"Serge Michiels\"],\n    \"createDate\": \"2019-10-02\",\n    \"lastModifyDate\": \"2019-10-02\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-10-02\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.2)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.tronios.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2F153.406+BeamZ+LED+Triple+Flex+centre+Pro_UK-NL-D-ESrev2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.beamzlighting.com/product/triple-flex-centre-pro-led/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=3pROoLUR4Tw\"\n    ]\n  },\n  \"helpWanted\": \"The 7-channel mode is derived from the manual, the 8-channel mode from the imported QLC+ fixture. Which one is correct? Or are there different versions of this fixture with different DMX configurations?\",\n  \"physical\": {\n    \"dimensions\": [320, 320, 160],\n    \"weight\": 1,\n    \"power\": 40,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"72 LEDs (24× red, 24× green, 24× blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null,  \"1\", null],\n        [null, null, null],\n        [ \"2\", null,  \"3\"]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"Is speed correct here?\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"soundControlled\": true,\n          \"helpWanted\": \"Is speed correct here?\"\n        }\n      ]\n    },\n    \"Motor Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Program Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Tilt $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Color Program $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.1\",\n          \"helpWanted\": \"Is this a static color (combination)? If so, which colors are activated with this capability? Same for following capabilities.\"\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.2\"\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.3\"\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.4\"\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.5\"\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.6\"\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.7\"\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.8\"\n        },\n        {\n          \"dmxRange\": [96, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.9\"\n        },\n        {\n          \"dmxRange\": [108, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.10\"\n        },\n        {\n          \"dmxRange\": [120, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.11\"\n        },\n        {\n          \"dmxRange\": [132, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.12\"\n        },\n        {\n          \"dmxRange\": [144, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.13\"\n        },\n        {\n          \"dmxRange\": [156, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.14\"\n        },\n        {\n          \"dmxRange\": [168, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.15\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.16\"\n        },\n        {\n          \"dmxRange\": [192, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.17\"\n        },\n        {\n          \"dmxRange\": [204, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.18\"\n        },\n        {\n          \"dmxRange\": [216, 227],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.19\"\n        },\n        {\n          \"dmxRange\": [228, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.20\"\n        },\n        {\n          \"dmxRange\": [240, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.21\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prog.22\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Color Program 1\",\n        \"Color Program 2\",\n        \"Color Program 3\",\n        \"Tilt 1\",\n        \"Tilt 2\",\n        \"Tilt 3\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Tilt 1\",\n        \"Tilt 2\",\n        \"Tilt 3\",\n        \"Motor Speed\",\n        \"Color Program 1\",\n        \"Color Program 2\",\n        \"Color Program 3\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/big-dipper/lp001.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LP001\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"simo\"],\n    \"createDate\": \"2019-08-26\",\n    \"lastModifyDate\": \"2019-08-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/1407632/Big-Dipper-Lp001.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=8HeYSPE-Ejk\",\n      \"https://www.youtube.com/watch?v=EfBSQLccAHE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [255, 255, 365],\n    \"weight\": 2.8,\n    \"power\": 180,\n    \"bulb\": {\n      \"type\": \"54× 3W LEDs (12 red, 18 green, 18 blue, 6 white)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Manual color selection\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color transition\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color shade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color pulse\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which color can be selected at which DMX value?\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Presets\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/big-dipper/ls90.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LS90\",\n  \"shortName\": \"LS90\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"zhefskie\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-09-12\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/899141/Big-Dipper-Led-Spot-Light-Ls90.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=TM9r-1u0gyI\"\n    ],\n    \"other\": [\n      \"https://www.qlcplus.org/forum/viewtopic.php?t=12338\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [245, 235, 350],\n    \"weight\": 7,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"90W LED\",\n      \"colorTemperature\": 8000,\n      \"lumens\": 4500\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Fuchsia\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue Green\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Yellow\",\n          \"colors\": [\"#ccaa00\"]\n        }\n      ]\n    },\n    \"Glass Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Metal Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Glass Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [36, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [72, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [108, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [144, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [180, 215],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Glass Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 89],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Glass Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Is this capability correct?\"\n        },\n        {\n          \"dmxRange\": [90, 167],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Glass Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\",\n          \"helpWanted\": \"Does the Gobo still rotate at DMX value 167?\"\n        },\n        {\n          \"dmxRange\": [168, 178],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Glass Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [179, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Glass Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Glass Gobo Shake\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Is the Gobo already shaking at DMX value 10?\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Glass Gobo Wheel\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Metal Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [27, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [54, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [81, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [108, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [135, 161],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [162, 188],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [189, 214],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Metal Gobo Shake\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Is the Gobo already shaking at DMX value 10?\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Metal Gobo Wheel\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"0%\",\n        \"distanceEnd\": \"100%\",\n        \"helpWanted\": \"Is focusing from far to near or vice-versa?\"\n      }\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 100],\n          \"type\": \"Prism\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all motors\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Glass Gobo Wheel\",\n        \"Glass Gobo Rotation\",\n        \"Glass Gobo Shake\",\n        \"Metal Gobo Wheel\",\n        \"Metal Gobo Shake\",\n        \"Focus\",\n        \"Prism\",\n        \"Pan/Tilt Speed\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/bitfocus/companion-v2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Companion v2.0\",\n  \"categories\": [\"Other\"],\n  \"meta\": {\n    \"authors\": [\"Ryan Goodwin\"],\n    \"createDate\": \"2023-05-06\",\n    \"lastModifyDate\": \"2023-05-06\"\n  },\n  \"comment\": \"Fixture to control Companion software via Artnet/DMX\",\n  \"links\": {\n    \"manual\": [\n      \"https://user.bitfocus.io/docs/companion\"\n    ],\n    \"productPage\": [\n      \"https://bitfocus.io/companion\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=jjbxzVrAG4M\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [0, 0, 0]\n  },\n  \"availableChannels\": {\n    \"Page\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Page\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 1\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 2\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 3\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 4\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 5\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 6\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 7\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 8\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 9\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 10\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 11\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 12\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 13\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 14\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 15\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 16\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 17\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 18\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 19\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 20\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 21\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 22\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 23\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 24\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 25\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 26\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 27\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 28\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 29\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 30\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 31\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 32\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 33\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 34\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 35\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 36\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 37\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 38\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 39\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 40\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 41\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 42\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 43\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 44\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 45\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 46\"\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 47\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 48\"\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 49\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 50\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 51\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 52\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 53\"\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 54\"\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 55\"\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 56\"\n        },\n        {\n          \"dmxRange\": [57, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 57\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 58\"\n        },\n        {\n          \"dmxRange\": [59, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 59\"\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 60\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 61\"\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 62\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 63\"\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 64\"\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 65\"\n        },\n        {\n          \"dmxRange\": [66, 66],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 66\"\n        },\n        {\n          \"dmxRange\": [67, 67],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 67\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 68\"\n        },\n        {\n          \"dmxRange\": [69, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 69\"\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 70\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 71\"\n        },\n        {\n          \"dmxRange\": [72, 72],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 72\"\n        },\n        {\n          \"dmxRange\": [73, 73],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 73\"\n        },\n        {\n          \"dmxRange\": [74, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 74\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 75\"\n        },\n        {\n          \"dmxRange\": [76, 76],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 76\"\n        },\n        {\n          \"dmxRange\": [77, 77],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 77\"\n        },\n        {\n          \"dmxRange\": [78, 78],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 78\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 79\"\n        },\n        {\n          \"dmxRange\": [80, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 80\"\n        },\n        {\n          \"dmxRange\": [81, 81],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 81\"\n        },\n        {\n          \"dmxRange\": [82, 82],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 82\"\n        },\n        {\n          \"dmxRange\": [83, 83],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 83\"\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 84\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 85\"\n        },\n        {\n          \"dmxRange\": [86, 86],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 86\"\n        },\n        {\n          \"dmxRange\": [87, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 87\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 88\"\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 89\"\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 90\"\n        },\n        {\n          \"dmxRange\": [91, 91],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 91\"\n        },\n        {\n          \"dmxRange\": [92, 92],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 92\"\n        },\n        {\n          \"dmxRange\": [93, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 93\"\n        },\n        {\n          \"dmxRange\": [94, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 94\"\n        },\n        {\n          \"dmxRange\": [95, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 95\"\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 96\"\n        },\n        {\n          \"dmxRange\": [97, 97],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 97\"\n        },\n        {\n          \"dmxRange\": [98, 98],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 98\"\n        },\n        {\n          \"dmxRange\": [99, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Page 99\"\n        },\n        {\n          \"dmxRange\": [100, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Bank\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Bank\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 1\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 2\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 3\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 4\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 5\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 6\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 7\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 8\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 9\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 10\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 11\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 12\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 13\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 14\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 15\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 16\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 17\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 18\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 19\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 20\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 21\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 22\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 23\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 24\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 25\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 26\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 27\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 28\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 29\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 30\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 31\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bank 32\"\n        },\n        {\n          \"dmxRange\": [33, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Button\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Button\"\n        },\n        {\n          \"dmxRange\": [11, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Button Down\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Button Up\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"00\",\n      \"channels\": [\n        \"Page\",\n        \"Bank\",\n        \"Button\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/blizzard/hotbox-exa.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"HotBox EXA\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-04-03\",\n    \"lastModifyDate\": \"2022-04-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://api.blizzard.lighting/public/Products/hotbox%20exa/downloads/HotBox%20EXA%20Manual%20Rev%20A%20(Web).pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.blizzardpro.com/products/hotbox-exa\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [127, 102, 127],\n    \"weight\": 2.7,\n    \"power\": 58,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7× 15W RGBAW+UV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [26, 26]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Fade, Color Change, Sound Active\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [128, 164],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [165, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade In / Fade Out, Auto Run\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Fade Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Maintenance\",\n          \"comment\": \"As set in the control menu display\"\n        },\n        {\n          \"dmxRange\": [6, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 0 = 8-bit, 256 dimming steps\"\n        },\n        {\n          \"dmxRange\": [56, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 1 = 32-bit, 0-25% intensity range\"\n        },\n        {\n          \"dmxRange\": [106, 155],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 2 = 32-bit, 0-50% intensity range\"\n        },\n        {\n          \"dmxRange\": [156, 205],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 3 = 32-bit, 0-75% intensity range\"\n        },\n        {\n          \"dmxRange\": [206, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 4 = 32-bit, full intensity dimming\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Hue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Strobe\",\n        \"Fade, Color Change, Sound Active\",\n        \"Fade Speed\",\n        \"Dimmer Control\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Strobe\",\n        \"Fade, Color Change, Sound Active\",\n        \"Fade Speed\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Hue\",\n        \"White\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/blizzard/hotbox-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"HotBox RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-04-11\",\n    \"lastModifyDate\": \"2022-04-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://api.blizzard.lighting/public/Products/hotbox%20rgbw/downloads/hotbox-manual-rev-b.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.blizzardpro.com/products/hotbox-rgbw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [127, 102, 127],\n    \"weight\": 2.7,\n    \"power\": 47,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7× 10W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [26, 26]\n    }\n  },\n  \"availableChannels\": {\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Value\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"12Hz Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"stop\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [15, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"12Hz\"\n        }\n      ]\n    },\n    \"20Hz Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"stop\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [15, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Fade, Color Change, Sound Active\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"comment\": \"\\\"Auto Run\\\" -- ch.8 ignored?\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active, Multicolor\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Fade Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Maintenance\",\n          \"comment\": \"As set in the control menu display\"\n        },\n        {\n          \"dmxRange\": [6, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 0 = 8-bit, 256 dimming steps\"\n        },\n        {\n          \"dmxRange\": [56, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 1 = 32-bit, 0-25% intensity range\"\n        },\n        {\n          \"dmxRange\": [106, 155],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 2 = 32-bit, 0-50% intensity range\"\n        },\n        {\n          \"dmxRange\": [156, 205],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 3 = 32-bit, 0-75% intensity range\"\n        },\n        {\n          \"dmxRange\": [206, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 4 = 32-bit, full intensity dimming\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Value\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"8-channel A\",\n      \"shortName\": \"8ACh\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"12Hz Strobe\",\n        \"Fade, Color Change, Sound Active\",\n        \"Fade Speed\"\n      ]\n    },\n    {\n      \"name\": \"8-channel B\",\n      \"shortName\": \"8bCh\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"20Hz Strobe\",\n        \"Fade, Color Change, Sound Active\",\n        \"Fade Speed\"\n      ]\n    },\n    {\n      \"name\": \"9-channel A\",\n      \"shortName\": \"9ACh\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"12Hz Strobe\",\n        \"Fade, Color Change, Sound Active\",\n        \"Fade Speed\",\n        \"Dimmer Control\"\n      ]\n    },\n    {\n      \"name\": \"9-channel B\",\n      \"shortName\": \"9bCh\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"20Hz Strobe\",\n        \"Fade, Color Change, Sound Active\",\n        \"Fade Speed\",\n        \"Dimmer Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/blizzard/puck-rgbaw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Puck RGBAW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"smokris\"],\n    \"createDate\": \"2018-04-23\",\n    \"lastModifyDate\": \"2018-08-06\"\n  },\n  \"links\": {\n    \"manual\": [\"https://cdn.shopify.com/s/files/1/1741/5055/files/puck-rgbaw-couch-potato-series_manual_rev_c.pdf\"],\n    \"other\": [\"https://github.com/OpenLightingProject/open-fixture-library/pull/462\"]\n  },\n  \"physical\": {\n    \"dimensions\": [210, 210, 63.5],\n    \"weight\": 1.8,\n    \"power\": 20,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"198x 10mm RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [21, 32]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer Simple\": {\n      \"name\": \"Dimmer\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Extended\": {\n      \"name\": \"Dimmer\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"dark\",\n          \"brightnessEnd\": \"bright\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Snap\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Snap on\"\n        }\n      ]\n    },\n    \"Color Snap Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Color Fade\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Fade on\"\n        }\n      ]\n    },\n    \"Color Fade Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"R\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"G\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"B\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"A\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"W\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"RG\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"RB\"\n        },\n        {\n          \"dmxRange\": [29, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6000\"],\n          \"comment\": \"RA\"\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8080\"],\n          \"comment\": \"RW\"\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"GB\"\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#92ff00\"],\n          \"comment\": \"GA\"\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ff80\"],\n          \"comment\": \"GW\"\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbfff\"],\n          \"comment\": \"BA\"\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8080ff\"],\n          \"comment\": \"BW\"\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf80\"],\n          \"comment\": \"AW\"\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdfff\"],\n          \"comment\": \"BAW\"\n        },\n        {\n          \"dmxRange\": [63, 66],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#baff5d\"],\n          \"comment\": \"GAW\"\n        },\n        {\n          \"dmxRange\": [67, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ffff\"],\n          \"comment\": \"GBW\"\n        },\n        {\n          \"dmxRange\": [71, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#92ff92\"],\n          \"comment\": \"GBA\"\n        },\n        {\n          \"dmxRange\": [75, 78],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9555\"],\n          \"comment\": \"RAW\"\n        },\n        {\n          \"dmxRange\": [79, 82],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff80ff\"],\n          \"comment\": \"RBW\"\n        },\n        {\n          \"dmxRange\": [83, 86],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6080\"],\n          \"comment\": \"RBA\"\n        },\n        {\n          \"dmxRange\": [87, 90],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff80\"],\n          \"comment\": \"RGW\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf00\"],\n          \"comment\": \"RGA\"\n        },\n        {\n          \"dmxRange\": [94, 97],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"RGB\"\n        },\n        {\n          \"dmxRange\": [98, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf80\"],\n          \"comment\": \"RGBA\"\n        },\n        {\n          \"dmxRange\": [102, 105],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"RGBW\"\n        },\n        {\n          \"dmxRange\": [106, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffea55\"],\n          \"comment\": \"RGAW\"\n        },\n        {\n          \"dmxRange\": [110, 113],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff95aa\"],\n          \"comment\": \"RBAW\"\n        },\n        {\n          \"dmxRange\": [114, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#baffba\"],\n          \"comment\": \"GBAW\"\n        },\n        {\n          \"dmxRange\": [118, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffeaaa\"],\n          \"comment\": \"RGBAW\"\n        },\n        {\n          \"dmxRange\": [121, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Dimmer Simple\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"Color Snap\",\n        \"Color Snap Speed\",\n        \"Color Fade\",\n        \"Color Fade Speed\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer Extended\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/blizzard/rokbox-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RokBox RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"DMS\"],\n    \"createDate\": \"2019-02-27\",\n    \"lastModifyDate\": \"2019-02-27\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2019-02-27\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.10.5b)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdn.shopify.com/s/files/1/1741/5055/files/rokbox_manual_rev_a.pdf?6943537019800087189\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20221208100256/https://www.blizzardpro.com/products/rokbox\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=jMTYqICI3Ng\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [229, 228, 165],\n    \"weight\": 3.3,\n    \"power\": 126,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18× 10W 4-in-1 LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade In\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade Out\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade In / Fade Out\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade In / Fade Out, Auto run\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"4 colors\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active multicolor\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"As set in control menu display\"\n        },\n        {\n          \"dmxRange\": [6, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 0 = 8bit, 256 dimming steps\"\n        },\n        {\n          \"dmxRange\": [56, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 1 = 32bit, 0…25% intensity range\"\n        },\n        {\n          \"dmxRange\": [106, 155],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 2 = 32bit, 0…50% intensity range\"\n        },\n        {\n          \"dmxRange\": [156, 205],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 3 = 32bit, 0…75% intensity range\"\n        },\n        {\n          \"dmxRange\": [206, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mode 4 = 32bit, full intensity dimming\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Hue\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Saturation\"\n      }\n    },\n    \"Value\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Value\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Dimmer Mode\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"HSV\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Value\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/crazy-spot-30.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Crazy Spot 30\",\n  \"shortName\": \"BTDJCrazySpot30\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"zampano\"],\n    \"createDate\": \"2018-05-30\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\"http://static.boomtonedj.com/pdf/manual/49/49502_manuelboomtonedjcrazyspot30.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=UAhS61D0V94\",\n      \"https://www.youtube.com/watch?v=7Cle6ROY1UQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [265, 300, 210],\n    \"weight\": 2.95,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"30W Cree LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [15, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [36, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [43, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [50, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [57, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Split colors\",\n          \"helpWanted\": \"Which DMX value selects which split color?\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"helpWanted\": \"Correct direction?\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"helpWanted\": \"Correct direction?\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"helpWanted\": \"Correct direction?\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"helpWanted\": \"Correct direction?\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on Pan/Tilt\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on color change\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on gobo change\"\n        },\n        {\n          \"dmxRange\": [120, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total reset\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Function\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Function\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-12x10w-5in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 12x10W 5in1\",\n  \"shortName\": \"BoomtoneSilentPar12x10W5in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49099_silentpar12x10w5in12016enfr.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-12x10w-5in1-p49099.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 10W RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-12x10w-6in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 12x10W 6in1\",\n  \"shortName\": \"BoomtoneSilentPar12x10W6in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49098_silentpar12x10w6in12016enfr.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-12x10w-6in1-p49098.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 10W RGBWAUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-12x3w-3in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 12x3W 3in1\",\n  \"shortName\": \"BoomtoneSilentPar12x3W3in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49097_silentpar12x3w3in12016enfr.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-12x3w-3in1-p49097.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 40,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-5x10w-5in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 5x10W 5in1\",\n  \"shortName\": \"BoomtoneSilentPar5x10W5in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49092_silentpar5x10w5in12016enfr2.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-5x10w-5in1-p49092.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 10W RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-5x10w-6in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 5x10W 6in1\",\n  \"shortName\": \"BoomtoneSilentPar5x10W6in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49093_silentpar5x10w6in12016enfr.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-5x10w-6in1-p49093.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 10W RGBWAUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-5x3w-3in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 5x3W 3in1\",\n  \"shortName\": \"BoomtoneSilentPar5x3W3in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49091_silentpar5x3w3in12016enfr.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-5x3w-3in1-p49091.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 20,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-7x10w-5in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 7x10W 5in1\",\n  \"shortName\": \"BoomtoneSilentPar7x10W5in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49095_silentpar7x10w5in12016enfr.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-7x10w-5in1-p49095.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 70,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7x 10W RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-7x10w-6in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 7x10W 6in1\",\n  \"shortName\": \"BoomtoneSilentPar7x10W6in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49096_silentpar7x10w6in12016enfr.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-7x10w-6in1-p49096.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 70,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7x 10W RGBWAUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/silentpar-7x3w-3in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SilentPAR 7x3W 3in1\",\n  \"shortName\": \"BoomtoneSilentPar7x3W3in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/49/49094_silentpar7x3w3in12016enfr.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.boomtonedj.com/boomtonedj-silentpar-7x3w-3in1-p49094.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wFqLpt4mC8I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 90, 252],\n    \"weight\": 3,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7x 3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [60, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\"\n        },\n        {\n          \"dmxRange\": [120, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [180, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Program Speed\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/boomtonedj/xtrem-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Xtrem LED\",\n  \"categories\": [\"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Tsunoo\"],\n    \"createDate\": \"2018-06-16\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://static.boomtonedj.com/pdf/manual/44/44625_xtremledmanual.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=gXyTYllokc4\"\n    ],\n    \"other\": [\n      \"https://www.qlcplus.org/forum/viewtopic.php?f=6&t=12319\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [245, 240, 245],\n    \"weight\": 3.4,\n    \"power\": 100,\n    \"bulb\": {\n      \"type\": \"2x 9W RGB LEDs, 36x White LEDs, 64x R/G/B LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom control\",\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Moon Flower Speed\",\n            \"Color / Show Speed\": \"Color\",\n            \"Color Strobe/Effect Speed / Unused\": \"Color Strobe/Effect Speed\",\n            \"Motor Speed / Unused\": \"Motor Speed\",\n            \"Strobe / Unused\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 1\",\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Motor Speed\",\n            \"Color / Show Speed\": \"Show Speed\",\n            \"Color Strobe/Effect Speed / Unused\": \"Unused 1\",\n            \"Motor Speed / Unused\": \"Unused 2\",\n            \"Strobe / Unused\": \"Unused 3\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 2\",\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Motor Speed\",\n            \"Color / Show Speed\": \"Show Speed\",\n            \"Color Strobe/Effect Speed / Unused\": \"Unused 1\",\n            \"Motor Speed / Unused\": \"Unused 2\",\n            \"Strobe / Unused\": \"Unused 3\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 3\",\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Motor Speed\",\n            \"Color / Show Speed\": \"Show Speed\",\n            \"Color Strobe/Effect Speed / Unused\": \"Unused 1\",\n            \"Motor Speed / Unused\": \"Unused 2\",\n            \"Strobe / Unused\": \"Unused 3\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 4\",\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Motor Speed\",\n            \"Color / Show Speed\": \"Show Speed\",\n            \"Color Strobe/Effect Speed / Unused\": \"Unused 1\",\n            \"Motor Speed / Unused\": \"Unused 2\",\n            \"Strobe / Unused\": \"Unused 3\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 5\",\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Motor Speed\",\n            \"Color / Show Speed\": \"Show Speed\",\n            \"Color Strobe/Effect Speed / Unused\": \"Unused 1\",\n            \"Motor Speed / Unused\": \"Unused 2\",\n            \"Strobe / Unused\": \"Unused 3\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 6\",\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Motor Speed\",\n            \"Color / Show Speed\": \"Show Speed\",\n            \"Color Strobe/Effect Speed / Unused\": \"Unused 1\",\n            \"Motor Speed / Unused\": \"Unused 2\",\n            \"Strobe / Unused\": \"Unused 3\"\n          }\n        },\n        {\n          \"dmxRange\": [204, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 7\",\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Motor Speed\",\n            \"Color / Show Speed\": \"Show Speed\",\n            \"Color Strobe/Effect Speed / Unused\": \"Unused 1\",\n            \"Motor Speed / Unused\": \"Unused 2\",\n            \"Strobe / Unused\": \"Unused 3\"\n          }\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Moon Flower Speed / Motor Speed\": \"Motor Speed\",\n            \"Color / Show Speed\": \"Show Speed\",\n            \"Color Strobe/Effect Speed / Unused\": \"Unused 1\",\n            \"Motor Speed / Unused\": \"Unused 2\",\n            \"Strobe / Unused\": \"Unused 3\"\n          }\n        }\n      ]\n    },\n    \"Moon Flower Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Color Strobe/Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [29, 57],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [58, 86],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [87, 115],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [116, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [145, 173],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [174, 202],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [203, 231],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"135bpm\",\n          \"comment\": \"cycle through the colors above\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        }\n      ]\n    },\n    \"Motor Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Show Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode (fixed to 0)\": {\n      \"defaultValue\": 0,\n      \"constant\": true,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom control\"\n        },\n        {\n          \"dmxRange\": [1, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 1\"\n        },\n        {\n          \"dmxRange\": [34, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 2\"\n        },\n        {\n          \"dmxRange\": [68, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 3\"\n        },\n        {\n          \"dmxRange\": [102, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 4\"\n        },\n        {\n          \"dmxRange\": [136, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 5\"\n        },\n        {\n          \"dmxRange\": [170, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 6\"\n        },\n        {\n          \"dmxRange\": [204, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 7\"\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Unused 1\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 2\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 3\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Custom control\",\n      \"shortName\": \"custom\",\n      \"channels\": [\n        \"Mode (fixed to 0)\",\n        \"Moon Flower Speed\",\n        \"Color\",\n        \"Color Strobe/Effect Speed\",\n        \"Motor Speed\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"Auto\",\n      \"shortName\": \"auto\",\n      \"channels\": [\n        \"Mode\",\n        \"Motor Speed\",\n        \"Show Speed\"\n      ]\n    },\n    {\n      \"name\": \"Combined\",\n      \"shortName\": \"combined\",\n      \"channels\": [\n        \"Mode\",\n        \"Moon Flower Speed / Motor Speed\",\n        \"Color / Show Speed\",\n        \"Color Strobe/Effect Speed / Unused\",\n        \"Motor Speed / Unused\",\n        \"Strobe / Unused\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/beam-fury-1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BEAM FURY-1\",\n  \"shortName\": \"Fury-1\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Arthur Moret\", \"Ken Harris\"],\n    \"createDate\": \"2023-05-13\",\n    \"lastModifyDate\": \"2023-05-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1492782829.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/beam-fury-1\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=C25Oex-b_HA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [235.6, 304.5, 185.6],\n    \"weight\": 6.17,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"60W LED\",\n      \"lumens\": 490\n    },\n    \"lens\": {\n      \"name\": \"Manual Frost\",\n      \"degreesMinMax\": [4, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\",\n        \"comment\": \"Range may be limited to 540deg in config menu\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"blackout by movement\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"All Motor Reset\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Pan Continuous Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\",\n          \"helpWanted\": \"Is this really fast…slow or slow…fast?\"\n        }\n      ]\n    },\n    \"Tilt Continuous Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\",\n          \"helpWanted\": \"Is this really fast…slow or slow…fast?\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Normal\"\n        },\n        {\n          \"dmxRange\": [8, 39],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"],\n          \"comment\": \"Red…Yellow\"\n        },\n        {\n          \"dmxRange\": [40, 71],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"Yellow…Green\"\n        },\n        {\n          \"dmxRange\": [72, 103],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"],\n          \"comment\": \"Green…Cyan\"\n        },\n        {\n          \"dmxRange\": [104, 135],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Cyan…Blue\"\n        },\n        {\n          \"dmxRange\": [136, 167],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"],\n          \"comment\": \"Blue…Magenta\"\n        },\n        {\n          \"dmxRange\": [168, 199],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"],\n          \"comment\": \"Magenta…Red\"\n        },\n        {\n          \"dmxRange\": [200, 231],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"],\n          \"comment\": \"Red…White\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Pan Continuous Rotation\",\n        \"Tilt Continuous Rotation\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Pan Continuous Rotation\",\n        \"Tilt Continuous Rotation\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/beamspot1-dmx-fc.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BEAMSPOT1-DMX FC\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Aleksey Khoroshev\"],\n    \"createDate\": \"2020-01-14\",\n    \"lastModifyDate\": \"2020-01-14\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1476262257.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/beamspot1-dmx-fc\"\n    ],\n    \"video\": [\n      \"https://www.facebook.com/MRProducts/videos/briteq-sound-lightshow-2016-hq-video/1103561746357817/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [124.5, 195.5, 172.25],\n    \"weight\": 1.23,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"15W RGBW LED\",\n      \"lumens\": 275\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 190],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"comment\": \"7 colors\"\n        },\n        {\n          \"dmxRange\": [201, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"100%\"\n        }\n      ]\n    },\n    \"Sound / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 24],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"comment\": \"7 colors\"\n        },\n        {\n          \"dmxRange\": [25, 34],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [35, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Extended Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 37],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [38, 67],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [68, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 247],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"helpWanted\": \"Is this the same sound controlled effect (7 colors) as in other channels?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB + Functions\",\n      \"shortName\": \"04CH RGB+DIM\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Functions\"\n      ]\n    },\n    {\n      \"name\": \"RGBW\",\n      \"shortName\": \"04CH RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Functions\",\n      \"shortName\": \"05CH RGBW+DIM\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Functions\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Master + Sound/Strobe\",\n      \"shortName\": \"06CH\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Master Dimmer\",\n        \"Sound / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Master + Strobe\",\n      \"shortName\": \"06CH+\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Master Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"Master + Strobe + Programs + RGBW\",\n      \"shortName\": \"07CH\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Extended Strobe\",\n        \"Programs\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/bt-coloray-120r.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BT-COLORAY 120R\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-03-06\",\n    \"lastModifyDate\": \"2019-03-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1521803829.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/bt-coloray-120r\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [272.5, 304.6, 241.7],\n    \"weight\": 4.8,\n    \"power\": 129,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"120W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 200],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [201, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB + Dim/Strb\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Dim + Strb\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Dim + Strb + DimSpeed\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/bt-coloray-18fcr.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BT-COLORAY 18FCR\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-03-06\",\n    \"lastModifyDate\": \"2019-03-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1550743398.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/bt-coloray-18fcr\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [273, 305, 192],\n    \"weight\": 5.28,\n    \"power\": 123,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18x 8W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 200],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [201, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB + Dim/Strb\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Dim + Strb\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Dim + Strb + DimSpeed\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/bt-coloray-60r.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BT-COLORAY 60R\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-03-06\",\n    \"lastModifyDate\": \"2019-03-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1521803829.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/bt-coloray-60r\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [272.5, 304.6, 241.7],\n    \"weight\": 4.8,\n    \"power\": 70,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"60W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 200],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [201, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB + Dim/Strb\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Dim + Strb\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Dim + Strb + DimSpeed\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/bt-ledrotor.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BT-LEDROTOR\",\n  \"shortName\": \"LEDROTOR\",\n  \"categories\": [\"Fan\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-12-11\",\n    \"lastModifyDate\": \"2018-12-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1537956760.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/bt-ledrotor\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=eP5CmRNi8KA\",\n      \"https://www.youtube.com/watch?v=tehBZU4Vp1A\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [700, 700, 94.5],\n    \"weight\": 18,\n    \"power\": 240,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"32× 3W UV LEDs, 720× 0.2W RGB LEDs\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null, null, null, null, null, \"A5\", null, null, null, null, null, null],\n        [\"F5\", null, null, null, null, null, \"A4\", null, null, null, null, null, \"B5\"],\n        [null, \"F4\", null, null, null, null, \"A3\", null, null, null, null, \"B4\", null],\n        [null, null, \"F3\", null, null, null, \"A2\", null, null, null, \"B3\", null, null],\n        [null, null, null, \"F2\", null, null, \"A1\", null, null, \"B2\", null, null, null],\n        [null, null, null, null, \"F1\", null, null, null, \"B1\", null, null, null, null],\n        [null, null, null, null, null, null, null, null, null, null, null, null, null],\n        [null, null, null, null, \"E1\", null, null, null, \"C1\", null, null, null, null],\n        [null, null, null, \"E2\", null, null, \"D1\", null, null, \"C2\", null, null, null],\n        [null, null, \"E3\", null, null, null, \"D2\", null, null, null, \"C3\", null, null],\n        [null, \"E4\", null, null, null, null, \"D3\", null, null, null, null, \"C4\", null],\n        [\"E5\", null, null, null, null, null, \"D4\", null, null, null, null, null, \"C5\"],\n        [null, null, null, null, null, null, \"D5\", null, null, null, null, null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Segment 1\": { \"name\": [\"^[A-F]1$\"] },\n      \"Segment 2\": { \"name\": [\"^[A-F]2$\"] },\n      \"Segment 3\": { \"name\": [\"^[A-F]3$\"] },\n      \"Segment 4\": { \"name\": [\"^[A-F]4$\"] },\n      \"Segment 5\": { \"name\": [\"^[A-F]5$\"] },\n      \"Blade A\": { \"name\": [\"^A[0-5]$\"] },\n      \"Blade B\": { \"name\": [\"^B[0-5]$\"] },\n      \"Blade C\": { \"name\": [\"^C[0-5]$\"] },\n      \"Blade D\": { \"name\": [\"^D[0-5]$\"] },\n      \"Blade E\": { \"name\": [\"^E[0-5]$\"] },\n      \"Blade F\": { \"name\": [\"^F[0-5]$\"] },\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Segment Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"],\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [23, 33],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 66],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [67, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [78, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [89, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"CFADE\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Meteor\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 121],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [122, 132],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [133, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 1\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 2\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [155, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 3\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 176],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 4\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [177, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 5\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [188, 198],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 6\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [199, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 7\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 8\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 9\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Flow 1…9\",\n          \"switchChannels\": {\n            \"Segment Effect Control\": \"Effect Speed\"\n          }\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Blades\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All blades switched on\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blade A switched on\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blade B switched on\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blade C switched on\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blade D switched on\",\n          \"helpWanted\": \"Is this capability's DMX range really wider than the others?\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blade E switched on\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blade F switched on\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blades A+B switched on\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blades A+C switched on\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blades A+D switched on\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blades A+C+E switched on\"\n        },\n        {\n          \"dmxRange\": [96, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random blades switched on/off\",\n          \"durationStart\": \"10s\",\n          \"durationEnd\": \"0.1s\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All blades switched on\"\n        }\n      ]\n    },\n    \"Fan Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"RGB Segment Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"CFADE\"\n        },\n        {\n          \"dmxRange\": [25, 42],\n          \"type\": \"Effect\",\n          \"effectName\": \"Meteor\"\n        },\n        {\n          \"dmxRange\": [43, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [61, 78],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [79, 93],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 1\"\n        },\n        {\n          \"dmxRange\": [94, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 2\"\n        },\n        {\n          \"dmxRange\": [111, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 3\"\n        },\n        {\n          \"dmxRange\": [128, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 4\"\n        },\n        {\n          \"dmxRange\": [145, 161],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 5\"\n        },\n        {\n          \"dmxRange\": [162, 178],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 6\"\n        },\n        {\n          \"dmxRange\": [179, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 7\"\n        },\n        {\n          \"dmxRange\": [196, 212],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 8\"\n        },\n        {\n          \"dmxRange\": [213, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 9\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Flow 1…9\"\n        }\n      ]\n    },\n    \"RGB Segment Effect Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"UV Dimmer\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"UV Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 13],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear dimmer curve\"\n        },\n        {\n          \"dmxRange\": [14, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square dimmer curve\"\n        },\n        {\n          \"dmxRange\": [20, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse square dimmer curve\"\n        },\n        {\n          \"dmxRange\": [26, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-curve dimmer curve\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"$pixelKey Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Easy\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Segment Effects\",\n        \"Segment Effect Control\",\n        \"Blades\",\n        \"Fan Rotation\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"RGB Segment Effects\",\n        \"RGB Segment Effect Speed\",\n        \"Blades\",\n        \"UV Dimmer\",\n        \"UV Strobe\",\n        \"Fan Rotation\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"33-channel\",\n      \"shortName\": \"33ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"Segment 1\",\n            \"Segment 2\",\n            \"Segment 3\",\n            \"Segment 4\",\n            \"Segment 5\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"Blade A\",\n            \"Blade B\",\n            \"Blade C\",\n            \"Blade D\",\n            \"Blade E\",\n            \"Blade F\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Dimmer\",\n            \"$pixelKey Strobe\"\n          ]\n        },\n        \"UV Dimmer\",\n        \"UV Strobe\",\n        \"Fan Rotation\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/bt-stagepar-6in1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BT-STAGEPAR 6in1\",\n  \"shortName\": \"BT-STAGEPAR6in1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"josequioss\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-10-13\",\n    \"lastModifyDate\": \"2019-10-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1517492038.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/bt-stagepar-6in1\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=dZgixI0Cq5Q\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [300, 275, 300],\n    \"weight\": 3.5,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 12W 6in1 LEDs (Red, Green, Blue, White, Amber, UV)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"All Colors\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\",\n        \"comment\": \"R+G+B+W+A\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"3200K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"Simple Strobe\": {\n      \"name\": \"Strobe\",\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Dimmer / Chase / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 190],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [201, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"100%\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Extended Strobe\": {\n      \"name\": \"Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 37],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [38, 67],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [68, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 247],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which color can be selected at which DMX values?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"All Colors\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"All Colors\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"All Colors\",\n        \"UV\",\n        \"Simple Strobe\"\n      ]\n    },\n    {\n      \"name\": \"3-channel+\",\n      \"shortName\": \"3ch+\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer / Chase / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Presets\"\n      ]\n    },\n    {\n      \"name\": \"9-channel+\",\n      \"shortName\": \"9ch+\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Extended Strobe\",\n        \"Programs\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/btx-cirrus-ii.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BTX-Cirrus II\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"rem5\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-04-11\",\n    \"lastModifyDate\": \"2022-04-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fr/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1581693398.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/fr/btx-cirrus-ii\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=RfdWRn76I-Q\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [391, 495, 286],\n    \"weight\": 16,\n    \"power\": 650,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 8000,\n      \"lumens\": 20600\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 60]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null, \"13\", null, \"14\", null, null],\n        [null, \"12\", null, null, null, \"15\", null],\n        [\"11\", null,  \"4\", null,  \"5\", null, \"16\"],\n        [null,  \"3\", null,  \"1\", null,  \"6\", null],\n        [\"10\", null,  \"2\", null,  \"7\", null, \"17\"],\n        [null,  \"9\", null, null, null, \"18\", null],\n        [null, null,  \"8\", null, \"19\", null, null]\n      ]\n    ]\n  },\n  \"templateChannels\": {\n    \"LED $pixelKey - Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"LED $pixelKey - Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"LED $pixelKey - Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"LED $pixelKey - White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"LED $pixelKey - Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"CTO\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [11, 54],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"8000K\",\n          \"colorTemperatureEnd\": \"7000K\"\n        },\n        {\n          \"dmxRange\": [55, 99],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"7000K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [100, 117],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6000K\",\n          \"colorTemperatureEnd\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [118, 144],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"5600K\",\n          \"colorTemperatureEnd\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [145, 188],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"5000K\",\n          \"colorTemperatureEnd\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [189, 224],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"4000K\",\n          \"colorTemperatureEnd\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"3200K\",\n          \"colorTemperatureEnd\": \"2500K\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 790 - Moroccan pink\",\n          \"colors\": [\"#ffb4a5\"]\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 157 - Pink\",\n          \"colors\": [\"#ff92a3\"]\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 332 - Special Rose Pink\",\n          \"colors\": [\"#ff3a89\"]\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 328 - Follies Pink\",\n          \"colors\": [\"#ff66c9\"]\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 345 - Fuchsia Pink\",\n          \"colors\": [\"#ce70d8\"]\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 194 - Surprise Pink\",\n          \"colors\": [\"#bf8ef0\"]\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 181 - Congo Blue\",\n          \"colors\": [\"#5304ab\"]\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 071 - Tokyo Blue\",\n          \"colors\": [\"#0000b4\"]\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 120 - Deep Blue\",\n          \"colors\": [\"#005fbe\"]\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 079 - Just Blue\",\n          \"colors\": [\"#3d8cd2\"]\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 132 - Medium Blue\",\n          \"colors\": [\"#01a0dc\"]\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 200 - Double CT Blue\",\n          \"colors\": [\"#91bef5\"]\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 161 - Slate Blue\",\n          \"colors\": [\"#7fd3f5\"]\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 201 - Full CT Blue\",\n          \"colors\": [\"#c3e1fa\"]\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 202 - Half CT Blue\",\n          \"colors\": [\"#d7f0ff\"]\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 117 - Steel Blue\",\n          \"colors\": [\"#b5faf5\"]\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 353 - Lighter Blue\",\n          \"colors\": [\"#63e8e3\"]\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 118 - Light Blue\",\n          \"colors\": [\"#02e1eb\"]\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 116 - Medium Blue Green\",\n          \"colors\": [\"#00c8b9\"]\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 124 - Dark Green\",\n          \"colors\": [\"#00dc78\"]\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 139 - Primary Green\",\n          \"colors\": [\"#4cc302\"]\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 089 - Moss Green\",\n          \"colors\": [\"#5bdc5b\"]\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 122 - Fem Green\",\n          \"colors\": [\"#79fa6f\"]\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 738 - JAS Green\",\n          \"colors\": [\"#aaff00\"]\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 088 - Lime Green\",\n          \"colors\": [\"#dcff64\"]\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 100 - Spring Yellow\",\n          \"colors\": [\"#f5ff00\"]\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 104 - Deep Amber\",\n          \"colors\": [\"#ffdc00\"]\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 179 - Chrome Orange\",\n          \"colors\": [\"#ffbe00\"]\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 105 - Orange\",\n          \"colors\": [\"#ffa000\"]\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 021 - Gold Amber\",\n          \"colors\": [\"#ff8c32\"]\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 778 - Millenium Gold\",\n          \"colors\": [\"#ff7600\"]\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 135 - Deep Golden Amber\",\n          \"colors\": [\"#ff5f00\"]\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 164 - Flame Red\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Open\",\n          \"helpWanted\": \"What happens at these \\\"Open\\\" capabilities?\"\n        },\n        {\n          \"dmxRange\": [180, 201],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [208, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Open\"\n        },\n        {\n          \"dmxRange\": [235, 249],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"random color macros\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Open\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"210deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Function off - rearmed\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout when pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout when pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inv. Square Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fast Dimmer Speed (halogen lamp simulation off)\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth Dimmer Speed (halogen lamp simulation off)\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable silence mode\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable silence mode\"\n        },\n        {\n          \"dmxRange\": [110, 219],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom reset\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt reset\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Complete reset\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Shape selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Generic\",\n          \"comment\": \"Dot (static)\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Ring 1 (static)\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Ring 2 (static)\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Generic\",\n          \"comment\": \"Dot + ring 1 (static)\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Generic\",\n          \"comment\": \"Dot + ring 2 (static)\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Generic\",\n          \"comment\": \"Ring 1 + ring 2 (static)\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Generic\",\n          \"comment\": \"Dot + ring 1 + ring 2 (static)\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 6\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 7\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 8\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 9\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 10\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 11\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 12\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 13\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 14\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 15\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 16\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 17\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 18\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 19\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 20\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 21\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 22\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 23\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 24\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 25\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 26\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 27\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 28\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 29\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 30\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 31\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 32\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 33\"\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 34\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 35\"\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 36\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 37\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 38\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 39\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 40\"\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 41\"\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 42\"\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 43\"\n        },\n        {\n          \"dmxRange\": [57, 57],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 44\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 45\"\n        },\n        {\n          \"dmxRange\": [59, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 46\"\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 47\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 48\"\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 49\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 50\"\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 51\"\n        },\n        {\n          \"dmxRange\": [66, 66],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 52\"\n        },\n        {\n          \"dmxRange\": [67, 67],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 53\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 54\"\n        },\n        {\n          \"dmxRange\": [69, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"Generic\",\n          \"comment\": \"Shape 55\"\n        },\n        {\n          \"dmxRange\": [71, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shape speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"Radius size, Static\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Shape Fade\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"Shape Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Shape Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Shape Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Shape White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shape Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shape Offset\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Shape Offset\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard (20 channels)\",\n      \"shortName\": \"Standard\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"Shapes (29 channels)\",\n      \"shortName\": \"Shapes\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Zoom\",\n        \"Shape selection\",\n        \"Shape speed\",\n        \"Shape Fade\",\n        \"Shape Red\",\n        \"Shape Green\",\n        \"Shape Blue\",\n        \"Shape White\",\n        \"Shape Dimmer\",\n        \"Shape Offset\"\n      ]\n    },\n    {\n      \"name\": \"Extended (77 channels)\",\n      \"shortName\": \"Extended\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Zoom\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"LED $pixelKey - Red\",\n            \"LED $pixelKey - Green\",\n            \"LED $pixelKey - Blue\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Extended RGBW (96 channels)\",\n      \"shortName\": \"Extended RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Zoom\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"LED $pixelKey - Red\",\n            \"LED $pixelKey - Green\",\n            \"LED $pixelKey - Blue\",\n            \"LED $pixelKey - White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Full (86 channels)\",\n      \"shortName\": \"Full\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Zoom\",\n        \"Shape selection\",\n        \"Shape speed\",\n        \"Shape Fade\",\n        \"Shape Red\",\n        \"Shape Green\",\n        \"Shape Blue\",\n        \"Shape White\",\n        \"Shape Dimmer\",\n        \"Shape Offset\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"LED $pixelKey - Red\",\n            \"LED $pixelKey - Green\",\n            \"LED $pixelKey - Blue\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Extended Dimmer (48 channels)\",\n      \"shortName\": \"Extended Dimmer\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Zoom\",\n        \"Shape selection\",\n        \"Shape speed\",\n        \"Shape Fade\",\n        \"Shape Red\",\n        \"Shape Green\",\n        \"Shape Blue\",\n        \"Shape White\",\n        \"Shape Dimmer\",\n        \"Shape Offset\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"LED $pixelKey - Dimmer\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/btx-titan.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BTX-Titan\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Wim Perneel\"],\n    \"createDate\": \"2020-03-28\",\n    \"lastModifyDate\": \"2020-03-28\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2020-03-28\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.2)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1479888588.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/btx-titan\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [391, 583, 287],\n    \"weight\": 15,\n    \"power\": 400,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"HRI 280\",\n      \"colorTemperature\": 7800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [2.7, 11]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep red\",\n          \"colors\": [\"#cc0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep blue\",\n          \"colors\": [\"#0000cc\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Azure\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark green\",\n          \"colors\": [\"#00cc00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff6600\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#ffcc99\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV filter\",\n          \"colors\": [\"#9900ff\"]\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Iris\"\n        },\n        {\n          \"type\": \"Iris\"\n        },\n        {\n          \"type\": \"Iris\"\n        },\n        {\n          \"type\": \"Iris\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Special Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX input: Wired DMX\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX input: Wireless DMX\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Eco mode (Lamp power 230W)\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard mode (Lamp power 280W)\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt speed mode\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt time mode\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout when pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout when pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout when colour wheel moving\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout when colour wheel moving\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout when gobo wheel moving\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout when gobo wheel moving\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp On, reset (total reset except pan/tilt reset)\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt reset\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colour system reset\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo wheels reset\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer/shutter\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom/focus/prism reset\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total reset\"\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp Off\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [27, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [46, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [55, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [73, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [82, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [101, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [110, 118],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [119, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [135, 138],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [139, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [148, 152],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [153, 157],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [158, 161],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [162, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [167, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [172, 176],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [186, 189],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 13,\n          \"slotNumberEnd\": 14\n        },\n        {\n          \"dmxRange\": [190, 215],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [218, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color selected by audio control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto random color selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Gobo Selection Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Static Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [10, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [16, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [28, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [34, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [40, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [46, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [52, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [58, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [64, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [70, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [76, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [82, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [202, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo selected by audio control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto random gobo selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [14, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [17, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 22],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [23, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [29, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 40],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [44, 46],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [47, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 52],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [53, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 67],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 75],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [76, 83],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [84, 91],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [92, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [108, 115],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [116, 123],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [124, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 137],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [138, 145],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [146, 153],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [162, 169],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 177],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [178, 185],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [186, 193],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [194, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [202, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo selected by audio control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto random gobo selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        }\n      ]\n    },\n    \"Gobo Rotation Angle\": {\n      \"fineChannelAliases\": [\"Gobo Rotation Angle fine\"],\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo Rotation Speed\": {\n      \"fineChannelAliases\": [\"Gobo Rotation Speed fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Prism\",\n          \"comment\": \"6-facet linear, indexing\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Angle\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Angle\",\n            \"Prism Rotation\": \"Prism Rotation Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Prism\",\n          \"comment\": \"6-facet linear, rotating\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet circular, indexing\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Angle\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Angle\",\n            \"Prism Rotation\": \"Prism Rotation Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet circular, rotating\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Prism\",\n          \"comment\": \"6-facet and 8-facet, indexing\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Angle\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Angle\",\n            \"Prism Rotation\": \"Prism Rotation Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Prism\",\n          \"comment\": \"6-facet and 8-facet, rotating\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 108],\n          \"type\": \"Prism\",\n          \"comment\": \"6-facet indexing, 8-facet rotating\",\n          \"helpWanted\": \"How does channel 15 'Prism Rotation' in 24ch mode behave here?\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Angle\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [109, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"6-facet rotating, 8-facet indexing\",\n          \"helpWanted\": \"How does channel 15 'Prism Rotation' in 24ch mode behave here?\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Angle\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 1\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 2\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 3\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 4\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 5\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 6\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 7\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 8\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 9\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 10\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 11\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 12\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 13\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 14\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 15\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 16\",\n          \"switchChannels\": {\n            \"6-Facet Prism Rotation\": \"6-Facet Prism Rotation Speed\",\n            \"8-Facet Prism Rotation\": \"8-Facet Prism Rotation Speed\",\n            \"Prism Rotation\": \"Prism Rotation Speed\"\n          }\n        }\n      ]\n    },\n    \"6-Facet Prism Rotation Angle\": {\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"6-Facet Prism Rotation Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"8-Facet Prism Rotation Angle\": {\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"8-Facet Prism Rotation Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism Rotation Angle\": {\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Prism Rotation Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"0%\",\n        \"frostIntensityEnd\": \"100%\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"11deg\",\n        \"angleEnd\": \"2.7deg\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Autofocus\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Autofocus off\"\n        },\n        {\n          \"dmxRange\": [1, 7],\n          \"type\": \"Focus\",\n          \"distance\": \"10m\",\n          \"comment\": \"rotating gobos\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Focus\",\n          \"distance\": \"15m\",\n          \"comment\": \"rotating gobos\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Focus\",\n          \"distance\": \"20m\",\n          \"comment\": \"rotating gobos\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Focus\",\n          \"distance\": \"25m\",\n          \"comment\": \"rotating gobos\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Focus\",\n          \"distance\": \"30m\",\n          \"comment\": \"rotating gobos\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Focus\",\n          \"distance\": \"35m\",\n          \"comment\": \"rotating gobos\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Focus\",\n          \"distance\": \"40m\",\n          \"comment\": \"rotating gobos\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Focus\",\n          \"distance\": \"45m\",\n          \"comment\": \"rotating gobos\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Focus\",\n          \"distance\": \"10m\",\n          \"comment\": \"static gobos\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Focus\",\n          \"distance\": \"15m\",\n          \"comment\": \"static gobos\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Focus\",\n          \"distance\": \"20m\",\n          \"comment\": \"static gobos\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Focus\",\n          \"distance\": \"25m\",\n          \"comment\": \"static gobos\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Focus\",\n          \"distance\": \"30m\",\n          \"comment\": \"static gobos\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Focus\",\n          \"distance\": \"35m\",\n          \"comment\": \"static gobos\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Focus\",\n          \"distance\": \"40m\",\n          \"comment\": \"static gobos\"\n        },\n        {\n          \"dmxRange\": [120, 126],\n          \"type\": \"Focus\",\n          \"distance\": \"45m\",\n          \"comment\": \"static gobos\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"Focus\",\n          \"distance\": \"far\",\n          \"comment\": \"Infinity\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Lamp power reduced to 230W\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"24-channel\",\n      \"shortName\": \"24ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Gobo Selection Speed\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Autofocus\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"25-channel\",\n      \"shortName\": \"25ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Gobo Selection Speed\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Prism\",\n        \"6-Facet Prism Rotation\",\n        \"8-Facet Prism Rotation\",\n        \"Frost\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Autofocus\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Color Wheel\",\n        \"Gobo Selection Speed\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism\",\n        \"6-Facet Prism Rotation\",\n        \"8-Facet Prism Rotation\",\n        \"Frost\",\n        \"Zoom\",\n        \"Focus\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/cob-slim-100-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"COB Slim 100-RGB\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Thierry\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-12-11\",\n    \"lastModifyDate\": \"2018-12-11\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-12-11\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.2 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1496150553.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/cob-slim100-rgb\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wAYsrW8YaZM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [245, 280, 140],\n    \"weight\": 3.46,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"100W COB RGB LED\",\n      \"colorTemperature\": 3200\n    },\n    \"lens\": {\n      \"name\": \"Other\",\n      \"degreesMinMax\": [15, 70]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 190],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control (7 colors)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [201, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Master dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 37],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [38, 67],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Sound Strobe\"\n        },\n        {\n          \"dmxRange\": [68, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 247],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Chase\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4LC channel\",\n      \"shortName\": \"4LC\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Mode\"\n      ]\n    },\n    {\n      \"name\": \"4+ channel\",\n      \"shortName\": \"4+\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Master dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6 channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Strobe\",\n        \"Effect\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/pro-beamer-zoom-indoor.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PRO BEAMER ZOOM INDOOR\",\n  \"shortName\": \"BriteqProBeamerZoom\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Artilom\"],\n    \"createDate\": \"2019-04-02\",\n    \"lastModifyDate\": \"2019-04-02\"\n  },\n  \"comment\": \"This fixture also applies to its Mk2 and Mk3 successors.\",\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1435914288.pdf\",\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1462951425.pdf\",\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1497009663.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/pro-beamer-zoom-indoor\",\n      \"https://briteq-lighting.com/pro-beamer-zoom-mk2-indoor\",\n      \"https://briteq-lighting.com/pro-beamer-zoom-mk3-indoor\"\n    ]\n  },\n  \"helpWanted\": \"In FULL mode, is Center/Outer correct? Is Step Time and Fade Time also used in other modes than TOUR?\",\n  \"physical\": {\n    \"dimensions\": [236, 191, 290],\n    \"weight\": 6.6,\n    \"power\": 128,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"7x 12W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [8, 40]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, \"O1\", null,     \"O2\", null],\n        [null, null, null,     null, null],\n        [\"O6\", null, \"Center\", null, \"O3\"],\n        [null, null, null,     null, null],\n        [null, \"O5\", null,     \"O4\", null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Outer\": { \"name\": [\"^O[1-6]$\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"fineChannelAliases\": [\"Master Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4900K\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5900K\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8500K\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 40],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 1\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 2\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 3\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 4\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 5\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 6\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 7\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 8\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 9\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 10\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.01\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.02\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.03\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.04\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.05\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.06\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.07\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.08\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.09\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.10\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        }\n      ]\n    },\n    \"Step Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"short\",\n        \"timeEnd\": \"long\",\n        \"comment\": \"Is short…long correct?\"\n      }\n    },\n    \"Fade Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"short\",\n        \"timeEnd\": \"long\",\n        \"comment\": \"Is short…long correct?\"\n      }\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use preset from menu\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear dimmer\"\n        },\n        {\n          \"dmxRange\": [30, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"66%\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"33%\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"8deg\",\n        \"angleEnd\": \"40deg\",\n        \"helpWanted\": \"Is it 8…40° or 40…8°?\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 200],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset zoom\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"helpWanted\": \"Which DMX values correspond to which color?\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Value\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"fineChannelAliases\": [\"Red $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"fineChannelAliases\": [\"Green $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"fineChannelAliases\": [\"Blue $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"fineChannelAliases\": [\"White $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Tour 8bit\",\n      \"shortName\": \"TOUR\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master / Step Time\",\n        \"Green Master / Fade Time\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Color Macro\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Speed\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"Tour 16bit\",\n      \"shortName\": \"TR16\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Red Master\",\n        \"Red Master fine\",\n        \"Green Master\",\n        \"Green Master fine\",\n        \"Blue Master\",\n        \"Blue Master fine\",\n        \"White Master\",\n        \"White Master fine\",\n        \"Color Macro\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Speed\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"ARC.1\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"DRGB\",\n      \"shortName\": \"AR1.D\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"RGBW\",\n      \"shortName\": \"ARC.2\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"DRGBW\",\n      \"shortName\": \"AR2.D\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"DRGBW + Strobe\",\n      \"shortName\": \"AR2.S\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"HSV\",\n      \"shortName\": \"HSV\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Value\"\n      ]\n    },\n    {\n      \"name\": \"DRGBW + Zoom\",\n      \"shortName\": \"AR2.Z\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"Full\",\n      \"shortName\": \"FULL\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Center\", \"Outer\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Red $pixelKey fine\",\n            \"Green $pixelKey\",\n            \"Green $pixelKey fine\",\n            \"Blue $pixelKey\",\n            \"Blue $pixelKey fine\",\n            \"White $pixelKey\",\n            \"White $pixelKey fine\"\n          ]\n        },\n        \"Color Macro\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Speed\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/briteq/pro-beamer-zoom-outdoor.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PRO BEAMER ZOOM OUTDOOR\",\n  \"shortName\": \"BriteqProBeamerZoomIP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-04-02\",\n    \"lastModifyDate\": \"2019-04-02\"\n  },\n  \"comment\": \"This fixture also applies to its Mk2 successor and the Rental variant.\",\n  \"links\": {\n    \"manual\": [\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1435914288.pdf\",\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1462951425.pdf\",\n      \"https://briteq-lighting.com/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1548924119.pdf\"\n    ],\n    \"productPage\": [\n      \"https://briteq-lighting.com/pro-beamer-zoom-outdoor\",\n      \"https://briteq-lighting.com/pro-beamer-zoom-mk2-outdoor\",\n      \"https://briteq-lighting.com/pro-beamer-zoom-rental\"\n    ]\n  },\n  \"helpWanted\": \"In FULL mode, is Center/Outer correct? Is Step Time and Fade Time also used in other modes than TOUR?\",\n  \"physical\": {\n    \"dimensions\": [236, 191, 355],\n    \"weight\": 6.6,\n    \"power\": 128,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"7x 12W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [8, 40]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, \"O1\", null,     \"O2\", null],\n        [null, null, null,     null, null],\n        [\"O6\", null, \"Center\", null, \"O3\"],\n        [null, null, null,     null, null],\n        [null, \"O5\", null,     \"O4\", null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Outer\": { \"name\": [\"^O[1-6]$\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"fineChannelAliases\": [\"Master Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4900K\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5900K\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8500K\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 40],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 1\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 2\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 3\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 4\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 5\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 6\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 7\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 8\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 9\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Auto 10\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Red Master\",\n            \"Green Master / Fade Time\": \"Green Master\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.01\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.02\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.03\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.04\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.05\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.06\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.07\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.08\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.09\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"PR.10\",\n          \"switchChannels\": {\n            \"Red Master / Step Time\": \"Step Time\",\n            \"Green Master / Fade Time\": \"Fade Time\"\n          }\n        }\n      ]\n    },\n    \"Step Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"short\",\n        \"timeEnd\": \"long\",\n        \"comment\": \"Is short…long correct?\"\n      }\n    },\n    \"Fade Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"short\",\n        \"timeEnd\": \"long\",\n        \"comment\": \"Is short…long correct?\"\n      }\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use preset from menu\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear dimmer\"\n        },\n        {\n          \"dmxRange\": [30, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"66%\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"33%\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"8deg\",\n        \"angleEnd\": \"40deg\",\n        \"helpWanted\": \"Is it 8…40° or 40…8°?\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 200],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset zoom\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"helpWanted\": \"Which DMX values correspond to which color?\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Value\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"fineChannelAliases\": [\"Red $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"fineChannelAliases\": [\"Green $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"fineChannelAliases\": [\"Blue $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"fineChannelAliases\": [\"White $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Tour 8bit\",\n      \"shortName\": \"TOUR\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master / Step Time\",\n        \"Green Master / Fade Time\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Color Macro\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Speed\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"Tour 16bit\",\n      \"shortName\": \"TR16\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Red Master\",\n        \"Red Master fine\",\n        \"Green Master\",\n        \"Green Master fine\",\n        \"Blue Master\",\n        \"Blue Master fine\",\n        \"White Master\",\n        \"White Master fine\",\n        \"Color Macro\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Speed\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"ARC.1\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"DRGB\",\n      \"shortName\": \"AR1.D\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"RGBW\",\n      \"shortName\": \"ARC.2\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"DRGBW\",\n      \"shortName\": \"AR2.D\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"DRGBW + Strobe\",\n      \"shortName\": \"AR2.S\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"HSV\",\n      \"shortName\": \"HSV\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Value\"\n      ]\n    },\n    {\n      \"name\": \"DRGBW + Zoom\",\n      \"shortName\": \"AR2.Z\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"Full\",\n      \"shortName\": \"FULL\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Center\", \"Outer\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Red $pixelKey fine\",\n            \"Green $pixelKey\",\n            \"Green $pixelKey fine\",\n            \"Blue $pixelKey\",\n            \"Blue $pixelKey fine\",\n            \"White $pixelKey\",\n            \"White $pixelKey fine\"\n          ]\n        },\n        \"Color Macro\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Speed\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/auro-beam-150.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Auro Beam 150\",\n  \"shortName\": \"CLABEAM150\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ray Tone\", \"Ryan Goodwin\"],\n    \"createDate\": \"2020-03-28\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/-406287878\"\n    ],\n    \"productPage\": [\n      \"https://www.gak.co.uk/en/cameo-auro-beam-150/913984\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Zsb151QKp7M\"\n    ]\n  },\n  \"helpWanted\": \"Is the matrix pixel order correct?\",\n  \"physical\": {\n    \"dimensions\": [375, 260, 180],\n    \"weight\": 5.5,\n    \"power\": 130,\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 1700\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null,  \"2\", null, null],\n        [ \"7\", null, null, null,  \"3\"],\n        [null, null,  \"1\", null, null],\n        [ \"6\", null, null, null,  \"4\"],\n        [null, null,  \"5\", null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Pan Continuous\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [9, 124],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [125, 139],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Tilt Continuous\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [9, 124],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [125, 139],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Strobe Simple\": {\n      \"name\": \"Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [9, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [33, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"bright blue\",\n          \"colors\": [\"#00aaff\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [57, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [69, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"turquoise\",\n          \"colors\": [\"#00ffbb\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"cold green\",\n          \"colors\": [\"#53ff7b\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [93, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"warm green\",\n          \"colors\": [\"#c2ff34\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [105, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"pink\",\n          \"colors\": [\"#ffaacc\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [117, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"magenta\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [129, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"purple\",\n          \"colors\": [\"#aa00ff\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"orange\",\n          \"colors\": [\"#ffbb00\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [153, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [165, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"warm white\",\n          \"colors\": [\"#ffddaa\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [177, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"cold white\",\n          \"colors\": [\"#aaddff\"],\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [189, 210],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 232],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color Macro Speed / Sound Sensitivity\": \"Color Macro Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Color Macro Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Auto Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [9, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [57, 72],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [73, 88],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [89, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 6\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [105, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 7\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 8\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [137, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 9\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [153, 168],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 10\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [169, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 11\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [185, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 12\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 216],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [217, 232],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode (lightning pattern)\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Auto Program Speed / Sound Sensitivity\": \"Auto Program Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Auto Program Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Auto Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Auto Mode Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [9, 23],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Blackout\",\n          \"switchChannels\": {\n            \"Auto Mode Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 81],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement Pattern (eight)\",\n          \"switchChannels\": {\n            \"Auto Mode Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [82, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement Pattern (ellipse)\",\n          \"switchChannels\": {\n            \"Auto Mode Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 197],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement Pattern (random)\",\n          \"switchChannels\": {\n            \"Auto Mode Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [198, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Auto Mode Speed / Sound Sensitivity\": \"Auto Mode Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Auto Mode Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Auto Mode Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Motor Reset (and blackout)\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macros\",\n        \"Color Macro Speed / Sound Sensitivity\",\n        \"Auto Mode\",\n        \"Auto Mode Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan Continuous\",\n        \"Tilt\",\n        \"Tilt Continuous\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Strobe Simple\"\n      ]\n    },\n    {\n      \"name\": \"19-channel\",\n      \"shortName\": \"19ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan Continuous\",\n        \"Tilt\",\n        \"Tilt Continuous\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Auto Program\",\n        \"Auto Program Speed / Sound Sensitivity\",\n        \"Auto Mode\",\n        \"Auto Mode Speed / Sound Sensitivity\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"41-channel\",\n      \"shortName\": \"41ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan Continuous\",\n        \"Tilt\",\n        \"Tilt Continuous\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Color Macros\",\n        \"Auto Program\",\n        \"Auto Program Speed / Sound Sensitivity\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/auro-spot-100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Auro Spot 100\",\n  \"shortName\": \"CLAS100\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-02-08\",\n    \"lastModifyDate\": \"2019-02-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLAS100/CLAS100_200_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.PDF\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vBKUMo8lxLk\",\n      \"https://www.youtube.com/watch?v=SVjWTA32sQQ\",\n      \"https://www.youtube.com/watch?v=Ut1U13wIY1Y\",\n      \"https://www.youtube.com/watch?v=dgaex6QQBOI&t=141\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [285, 480, 180],\n    \"weight\": 8.75,\n    \"power\": 175,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"60W white LED\",\n      \"colorTemperature\": 10000,\n      \"lumens\": 2100\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#ccbfff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"235deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Strobe Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [21, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [36, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [44, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [51, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [59, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [66, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [74, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [81, 88],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [89, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [104, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [111, 118],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [26, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [46, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [66, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [86, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [106, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Gobo Shake\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"12.5%\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"25%\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"37.5%\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"62.5%\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"75%\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"87.5%\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"100%\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"Prism\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Prism\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"Prism\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"0%\",\n        \"distanceEnd\": \"100%\",\n        \"helpWanted\": \"Is this near…far or far…near?\"\n      }\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [39, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [71, 102],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [103, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [135, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [167, 198],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [199, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pan/Tilt Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [48, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [90, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [132, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt inverse\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [174, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ellipse\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-Curve Dimmer Curve\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Device Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Blackout while Moving on\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Blackout while Moving off\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Pan on\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Pan off\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Tilt on\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Tilt off\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Silent Fan on\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Silent Fan off\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan / tilt\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset effects (prism, gobo, ...)\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all functions\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Strobe Functions\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Shake\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"22-channel\",\n      \"shortName\": \"22ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe Functions\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Shake\",\n        \"Prism\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Pan/Tilt Macro\",\n        \"Pan/Tilt Macro Speed\",\n        \"Dimmer Curve\",\n        \"Pan/Tilt Speed\",\n        \"Device Settings\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/auro-spot-200.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Auro Spot 200\",\n  \"shortName\": \"CLAS200\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-02-08\",\n    \"lastModifyDate\": \"2019-02-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLAS200/CLAS200_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/moving-lights/moving-heads/2072/auro-spot-200\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=mqNAfW646yQ\",\n      \"https://www.youtube.com/watch?v=SVjWTA32sQQ\",\n      \"https://www.youtube.com/watch?v=Ut1U13wIY1Y\",\n      \"https://www.youtube.com/watch?v=dgaex6QQBOI&t=141\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [285, 480, 180],\n    \"weight\": 8.75,\n    \"power\": 220,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"100W white LED\",\n      \"colorTemperature\": 10000,\n      \"lumens\": 3250\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#ccbfff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"235deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Strobe Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [21, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [36, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [44, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [51, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [59, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [66, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [74, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [81, 88],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [89, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [104, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [111, 118],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [26, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [46, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [66, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [86, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [106, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Gobo Shake\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"12.5%\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"25%\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"37.5%\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"62.5%\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"75%\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"87.5%\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"100%\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"Prism\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Prism\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"Prism\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"0%\",\n        \"distanceEnd\": \"100%\",\n        \"helpWanted\": \"Is this near…far or far…near?\"\n      }\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [39, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [71, 102],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [103, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [135, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [167, 198],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [199, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pan/Tilt Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [48, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [90, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [132, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt inverse\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [174, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ellipse\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-Curve Dimmer Curve\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Device Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Blackout while Moving on\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Blackout while Moving off\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Pan on\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Pan off\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Tilt on\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Tilt off\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Silent Fan on\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Silent Fan off\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan / tilt\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset effects (prism, gobo, ...)\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all functions\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Strobe Functions\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Shake\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"22-channel\",\n      \"shortName\": \"22ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe Functions\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Shake\",\n        \"Prism\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Pan/Tilt Macro\",\n        \"Pan/Tilt Macro Speed\",\n        \"Dimmer Curve\",\n        \"Pan/Tilt Speed\",\n        \"Device Settings\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/auro-spot-300.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Auro Spot 300\",\n  \"shortName\": \"CLAS300\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-02-08\",\n    \"lastModifyDate\": \"2019-02-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.adamhall.com/shop/us-en/downloads/file/id/-354715156\"\n    ],\n    \"productPage\": [\n      \"https://www.adamhall.com/shop/us-en/archiv/2074/auro-spot-300?c=5621\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [285, 485, 180],\n    \"weight\": 8.75,\n    \"power\": 320,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"180W white LED\",\n      \"colorTemperature\": 9300,\n      \"lumens\": 4371\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#ccbfff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"235deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Strobe Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [21, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [36, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [44, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [51, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [59, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [66, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [74, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [81, 88],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [89, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [104, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [111, 118],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [26, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [46, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [66, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [86, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [106, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Gobo 1 Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Gobo 1 Shake\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"12.5%\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"25%\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"37.5%\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"62.5%\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"75%\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"87.5%\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"100%\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [21, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [36, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [51, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [66, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [81, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [96, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [111, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Gobo 2 Shake\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"12.5%\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"25%\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"37.5%\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"62.5%\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"75%\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"87.5%\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"100%\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"Prism\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Prism\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"Prism\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"0%\",\n        \"distanceEnd\": \"100%\",\n        \"helpWanted\": \"Is this near…far or far…near?\"\n      }\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [39, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [71, 102],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [103, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [135, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [167, 198],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [199, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pan/Tilt Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [48, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [90, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [132, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt inverse\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [174, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ellipse\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-Curve Dimmer Curve\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Device Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Blackout while Moving on\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Blackout while Moving off\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Pan on\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Pan off\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Tilt on\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Tilt off\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Silent Fan on\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Silent Fan off\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan / tilt\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset effects (prism, gobo, ...)\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all functions\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Strobe Functions\",\n        \"Color Wheel\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 Rotation\",\n        \"Gobo 1 Shake\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 Shake\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"24-channel\",\n      \"shortName\": \"24ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe Functions\",\n        \"Color Wheel\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 Rotation\",\n        \"Gobo 1 Shake\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 Shake\",\n        \"Prism\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Pan/Tilt Macro\",\n        \"Pan/Tilt Macro Speed\",\n        \"Dimmer Curve\",\n        \"Pan/Tilt Speed\",\n        \"Device Settings\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/auro-spot-400.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Auro Spot 400\",\n  \"shortName\": \"CLAS400\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-02-08\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLAS400/CLAS400_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adamhall.com/shop/tt-en/archiv/2075/auro-spot-400\",\n      \"https://www.simplysoundandlighting.co.uk/products/cameo-auroa-spot-400-led-moving-head\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=dgaex6QQBOI&t=141\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [405, 565, 285],\n    \"weight\": 15.6,\n    \"power\": 290,\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"180W white LED\",\n      \"colorTemperature\": 9300,\n      \"lumens\": 4470\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Color Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow warm\",\n          \"colors\": [\"#ffd500\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#ccbfff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lime\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Turquoise\",\n          \"colors\": [\"#00ffbb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Warm White\",\n          \"colors\": [\"#fffbf2\"],\n          \"colorTemperature\": \"CTO\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cold White\",\n          \"colors\": [\"#f2f6fe\"],\n          \"colorTemperature\": \"CTB\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Prism Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Prism\",\n          \"facets\": 3\n        },\n        {\n          \"type\": \"Prism\",\n          \"facets\": 5\n        },\n        {\n          \"type\": \"Prism\",\n          \"facets\": 8\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Strobe Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel 1\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Color Wheel 2\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 22],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [23, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [40, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [57, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [74, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [91, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [108, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Gobo 1 Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Gobo 1 Shake\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"12.5%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"25%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"37.5%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"50%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"62.5%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"75%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"87.5%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeed\": \"100%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [34, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [48, 61],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [62, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [90, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [104, 117],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Gobo 2 Shake\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"12.5%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"25%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"37.5%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"50%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"62.5%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"75%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"87.5%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeed\": \"100%\",\n          \"shakeAngleStart\": \"narrow\",\n          \"shakeAngleEnd\": \"wide\"\n        }\n      ]\n    },\n    \"Prism Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        }\n      ]\n    },\n    \"Prism Wheel Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Prism Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Prism Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Prism Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Prism Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Prism Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"0%\",\n        \"distanceEnd\": \"100%\",\n        \"helpWanted\": \"Is this near…far or far…near?\"\n      }\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [31, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [56, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [81, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [106, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [131, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [156, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [181, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [206, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pan/Tilt Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [48, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [90, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [132, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt inverse\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [174, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ellipse\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [192, 250],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-Curve Dimmer Curve\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Device Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 37],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Blackout while Moving on\"\n        },\n        {\n          \"dmxRange\": [38, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Blackout while Moving off\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Pan on\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Pan off\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Tilt on\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Tilt off\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Silent Fan on\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Silent Fan off\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan / tilt\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset effects (iris, prism, gobo, ...)\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all functions\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"19-channel\",\n      \"shortName\": \"19ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Strobe Functions\",\n        \"Color Wheel 1\",\n        \"Color Wheel 2\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 Rotation\",\n        \"Gobo 1 Shake\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 Shake\",\n        \"Prism Wheel\",\n        \"Prism Wheel Rotation\",\n        \"Focus\",\n        \"Frost\",\n        \"Pan/Tilt Speed\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"27-channel\",\n      \"shortName\": \"27ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe Functions\",\n        \"Color Wheel 1\",\n        \"Color Wheel 2\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 Rotation\",\n        \"Gobo 1 Shake\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 Shake\",\n        \"Prism Wheel\",\n        \"Prism Wheel Rotation\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Frost\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Pan/Tilt Macro\",\n        \"Pan/Tilt Macro Speed\",\n        \"Dimmer Curve\",\n        \"Pan/Tilt Speed\",\n        \"Device Settings\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/auro-spot-z300.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Auro Spot Z300\",\n  \"shortName\": \"Z300\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Kerni\", \"Flo Edelmann\"],\n    \"createDate\": \"2026-01-28\",\n    \"lastModifyDate\": \"2026-01-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://portal.adamhall.com/api/v1/customer-dlc/article/download/8120dbc1-c7b8-4ccf-84dd-1712846cd277\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/moving-lights/moving-heads/20393/auro-spot-z300\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=mQZL-_6MVaE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [282, 469, 186],\n    \"weight\": 11.2,\n    \"power\": 200,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 4000,\n      \"lumens\": 7500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 25]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep Red\",\n          \"colors\": [\"#8b0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Medium Blue\",\n          \"colors\": [\"#0000cd\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep Green\",\n          \"colors\": [\"#006400\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber/Deep Orange\",\n          \"colors\": [\"#ff8c00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO 3200K\",\n          \"colors\": [\"#ffd6aa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Congo Blue\",\n          \"colors\": [\"#4169e1\"]\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [12, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [18, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [24, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [30, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [36, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [42, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [48, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [54, 192],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [193, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is it really slow…fast here and fast…slow for DMX values 225…255?\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [21, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [36, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [51, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [66, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [81, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [96, 110],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [111, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 140],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 155],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [156, 170],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [171, 185],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [186, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is it really slow…fast here and fast…slow for DMX values 225…255?\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is it really slow…fast here and fast…slow for DMX values 193…255?\"\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [21, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [36, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [51, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [66, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [81, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [96, 110],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [111, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 140],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 155],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [156, 170],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [171, 185],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [186, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is it really slow…fast here and fast…slow for DMX values 225…255?\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"0%\",\n        \"distanceEnd\": \"100%\"\n      }\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"Prism 1 circle\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"Prism 2 linear\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is it really slow…fast here and fast…slow for DMX values 193…255?\"\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"0%\",\n          \"frostIntensityEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Device settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [16, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [26, 35],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Invert Pan on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Invert Pan off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [46, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Invert Tilt on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [56, 65],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Invert Tilt off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [66, 75],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display backlight on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [76, 85],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display backlight off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve linear\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [96, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve exponential\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [106, 115],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve logarithmic\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [116, 125],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve S-Curve\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [126, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM frequency 800Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [136, 145],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM frequency 1200Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [146, 155],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM frequency 2000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [156, 165],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM frequency 3600Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [166, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM frequency 12kHz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [176, 185],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM frequency 25kHz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [186, 195],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [196, 205],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan silent\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [206, 215],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan / Tilt\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [216, 225],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset head only\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all functions\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Auto Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [68, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [130, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Pan/Tilt Auto Movement\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [41, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [76, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [111, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt (inverse)\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [146, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [181, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle (inverse)\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        }\n      ]\n    },\n    \"Pan/Tilt speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Static Gobo Wheel\",\n        \"Zoom\",\n        \"Focus\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Device settings\"\n      ]\n    },\n    {\n      \"name\": \"20-channel\",\n      \"shortName\": \"20ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Static Gobo Wheel\",\n        \"Zoom\",\n        \"Focus\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Auto Program\",\n        \"Pan/Tilt Auto Movement\",\n        \"Pan/Tilt speed\",\n        \"Device settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/flash-matrix-250.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flash Matrix 250\",\n  \"shortName\": \"CLFM250\",\n  \"categories\": [\"Matrix\", \"Strobe\", \"Blinder\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-12-28\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"links\": {\n    \"manual\": [\"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLFM250/CLFM250_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"]\n  },\n  \"physical\": {\n    \"dimensions\": [305, 310, 105],\n    \"weight\": 4,\n    \"power\": 125,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"25x 6W LEDs (cool white)\",\n      \"lumens\": 9216\n    },\n    \"lens\": {\n      \"degreesMinMax\": [50, 50]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [5, 5, 1]\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Master Dimmer Invert\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Invert Dimmer (Switch active and inactive LEDs)\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"Strobe Simple\": {\n      \"name\": \"Strobe\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Strobe Extended\": {\n      \"name\": \"Strobe\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\",\n          \"comment\": \"break effect\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"512ms\"\n      }\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [29, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [52, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [75, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\"\n        },\n        {\n          \"dmxRange\": [98, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\"\n        },\n        {\n          \"dmxRange\": [121, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 6\"\n        },\n        {\n          \"dmxRange\": [144, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 7\"\n        },\n        {\n          \"dmxRange\": [167, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 8\"\n        },\n        {\n          \"dmxRange\": [190, 212],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 9\"\n        },\n        {\n          \"dmxRange\": [213, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 10\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 11\"\n        }\n      ]\n    },\n    \"Auto Programs / Sound Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [6, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [108, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [126, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 6\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 161],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 7\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [162, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 8\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 197],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 9\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [198, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 10\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 11\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Pattern Type\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Letters\"\n        },\n        {\n          \"dmxRange\": [132, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Numbers & Symbols\"\n        }\n      ]\n    },\n    \"Pattern Select\": {\n      \"defaultValue\": 160,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Effect\",\n          \"effectName\": \"A / 0\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"B / 1\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"C / 2\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"D / 3\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"E / 4\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"F / 5\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"G / 6\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"H / 7\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"I / 8\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"J / 9\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"K / +\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"L / -\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"M / :\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"N / %\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"O / !\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"P / ?\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Q / =\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"R / <\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Effect\",\n          \"effectName\": \"S / >\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"T / ^\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"U / ˅\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"V / [\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"W / ]\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"X / ↑\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Y / →\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Z / ←\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Empty / ↓\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Empty / ↖\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"Empty / ↗\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Empty / ↙\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Empty / ↘\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Empty / All on\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Empty / Empty\"\n        }\n      ]\n    },\n    \"Pattern Speed / Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [6, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Position: 0° / 45° / 90° / 135° / 180° / 225° / 270° / 315°\"\n        },\n        {\n          \"dmxRange\": [48, 69],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"EffectSpeed\",\n          \"comment\": \"downwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [102, 133],\n          \"type\": \"EffectSpeed\",\n          \"comment\": \"upwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [134, 165],\n          \"type\": \"EffectSpeed\",\n          \"comment\": \"rightwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [166, 197],\n          \"type\": \"EffectSpeed\",\n          \"comment\": \"leftwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [198, 229],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Pattern Transition\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"EffectDuration\",\n          \"durationStart\": \"0s\",\n          \"durationEnd\": \"5s\"\n        }\n      ]\n    },\n    \"Pattern Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade\",\n          \"parameterStart\": \"low\",\n          \"parameterEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wake\",\n          \"parameterStart\": \"low\",\n          \"parameterEnd\": \"high\"\n        }\n      ]\n    },\n    \"Pattern Invert / Swap\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Invert\"\n        },\n        {\n          \"dmxRange\": [85, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Swap\"\n        },\n        {\n          \"dmxRange\": [164, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Invert and Swap\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer LED $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Auto Programs\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe Extended\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe Extended\",\n        \"Flash Duration\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe Extended\",\n        \"Flash Duration\",\n        \"Auto Programs / Sound Mode\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe Extended\",\n        \"Pattern Type\",\n        \"Pattern Select\",\n        \"Pattern Speed / Sound Sensitivity\",\n        \"Pattern Transition\",\n        \"Pattern Effect\",\n        \"Pattern Invert / Swap\",\n        \"Master Dimmer Invert\"\n      ]\n    },\n    {\n      \"name\": \"25-channel\",\n      \"shortName\": \"25ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer LED $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"30-channel\",\n      \"shortName\": \"30ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe Simple\",\n        \"Flash Duration\",\n        \"Auto Programs / Sound Mode\",\n        \"Program Speed / Sound Sensitivity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer LED $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/flat-par-can-rgb-10-ir.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flat PAR Can RGB 10 IR\",\n  \"shortName\": \"CLPFLAT1RGB10IR\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-03-06\",\n    \"lastModifyDate\": \"2024-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLPFLAT1RGB10IR/CLPFLAT1RGB10IR_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\",\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLPFLAT1TRI3WIR/CLPFLAT1TRI3WIR_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://blog.adamhall.com/en/2015/03/09/cameo-clpflat1rgb10ir-led-scheinwerfer-fur-kleine-events-testbericht-von-delamar-de/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=7otHVQmaCfw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 175, 115],\n    \"weight\": 1.2,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"144x 10mm LEDs (48 red, 48 green, 48 blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14, 14]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Macro Advanced\": {\n      \"name\": \"Color Macro\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [5, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [16, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [27, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [38, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [49, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [60, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Color Macro\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Macro Advanced\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2 (RGB)\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macro Advanced\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/flat-par-can-tri-5x-3w-ir.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flat PAR Can Tri 5x 3W IR\",\n  \"shortName\": \"CLPFLAT1TRI5X3WIR\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-03-06\",\n    \"lastModifyDate\": \"2019-03-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLPFLAT1TRI3WIR/CLPFLAT1TRI3WIR_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\",\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLPFLAT1RGB10IR/CLPFLAT1RGB10IR_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=-XZnF7kOvnc\",\n      \"https://www.youtube.com/watch?v=uX1ofuX5T3A\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 175, 115],\n    \"weight\": 1.2,\n    \"power\": 20,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0%\",\n        \"speedEnd\": \"100%\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Macro Advanced\": {\n      \"name\": \"Color Macro\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [5, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [16, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [27, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [38, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [49, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [60, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Color Macro\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Color Macro Advanced\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2 (RGB)\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macro Advanced\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/flat-par-can-tri-7x-3w-ir.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flat PAR Can Tri 7x 3W IR\",\n  \"shortName\": \"CLPFLAT1TRI3WIR\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Fabian\"],\n    \"createDate\": \"2018-09-22\",\n    \"lastModifyDate\": \"2024-09-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLPFLAT1TRI3WIR/CLPFLAT1TRI3WIR_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\",\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLPFLAT1RGB10IR/CLPFLAT1RGB10IR_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.coolshop.co.uk/product/cameo-flat-par-tri-3w-ir-led-rgb-par-light-white/AB5D8Y/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=mKLHiZFlf4Y\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 175, 115],\n    \"weight\": 1.2,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7x 3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Color Macro Advanced\": {\n      \"name\": \"Color Macro\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [5, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [16, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [27, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [38, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [49, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [60, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Color Macro\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Macro Advanced\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2 (RGB)\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macro Advanced\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/flat-pro-18.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flat Pro 18\",\n  \"shortName\": \"CLPFLATPRO18\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-07-14\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLPFLATPRO7/CLPFLATPRO7-12-18_Cameo_Bedienungsanleitung_EN_DE_FR_ES.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=MtzWwkFTuFk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [280, 280, 130],\n    \"weight\": 7.4,\n    \"power\": 200,\n    \"DMXconnector\": \"3-pin and 5-pin\"\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro Simple\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [17, 33],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [34, 50],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [51, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [68, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [85, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [102, 118],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [119, 135],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [136, 152],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8adc\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [153, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffaa\"],\n          \"comment\": \"Light Green\"\n        },\n        {\n          \"dmxRange\": [170, 186],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [187, 203],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [204, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffcc00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [221, 237],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2f6fe\"],\n          \"colorTemperature\": \"cold\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffbf2\"],\n          \"colorTemperature\": \"warm\",\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Color Macro Advanced\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 10],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8adc\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffaa\"],\n          \"comment\": \"Light Green\"\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffcc00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2f6fe\"],\n          \"colorTemperature\": \"cold\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffbf2\"],\n          \"colorTemperature\": \"warm\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0%\",\n        \"speedEnd\": \"100%\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macro Simple\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macro Advanced\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Color Macro Advanced\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/flat-pro-flood-600-ip65.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flat Pro Flood 600 IP65\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Nicolas Roux SLP EVENEMENTS\", \"Flo Edelmann\"],\n    \"createDate\": \"2021-12-03\",\n    \"lastModifyDate\": \"2021-12-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/1131938970\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/static-lighting/blacklights/9564/flood-600-ip65\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Pg6MJoBzkoI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 180, 120],\n    \"weight\": 4,\n    \"power\": 90,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"9× 12W RGBWAUV 6in1 LEDs\",\n      \"lumens\": 2119\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow warm\",\n          \"colors\": [\"#ffdd00\"]\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#00ff80\"]\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#7f00ff\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#fff8c8\"]\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#c8f8ff\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"20ms\",\n        \"durationEnd\": \"510ms\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"7200K\",\n          \"colorTemperatureEnd\": \"3200K\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Flash Duration\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Flash Duration\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Macros\",\n        \"Color Temperature\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/flat-pro-flood-ip65-tri.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flat Pro Flood IP65 Tri\",\n  \"shortName\": \"CLFLOODIP65TRI\",\n  \"categories\": [\"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-12-25\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"links\": {\n    \"manual\": [\"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLFLOODIP65TRI/CLFLOODIP65TRI_CAMEO_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 180, 120],\n    \"weight\": 3.6,\n    \"power\": 75,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"60 W COB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros Simple\": {\n      \"name\": \"Color Macros\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color Macros Extended\": {\n      \"name\": \"Color Macros\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 26],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [27, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [38, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [49, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [60, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macros Simple\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros Extended\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros Extended\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/gobo-scanner-80.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Gobo Scanner 80\",\n  \"shortName\": \"CLSCAN80W\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-11-30\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"comment\": \"Also known as \\\"G-Scan 80\\\"\",\n  \"links\": {\n    \"manual\": [\"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLSCAN80W/CLSCAN80W_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"],\n    \"video\": [\"https://www.youtube.com/watch?v=QebhUtJIB78\"]\n  },\n  \"physical\": {\n    \"dimensions\": [190, 150, 450],\n    \"weight\": 4.9,\n    \"power\": 130,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"80 W cool white LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Warm Yellow\",\n          \"colors\": [\"#f9d716\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lime\",\n          \"colors\": [\"#bfff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"90deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"510ms\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [19, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [32, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [45, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [58, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [71, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [84, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [97, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [110, 122],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [123, 128],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [42, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [54, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [66, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [78, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [90, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [102, 113],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [114, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 137],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [138, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [150, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [162, 173],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [174, 185],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [186, 197],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [198, 209],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 221],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [222, 231],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [232, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [244, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [41, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [76, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [111, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt invers\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [146, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [181, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle invers\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 55],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Pan on\"\n        },\n        {\n          \"dmxRange\": [56, 105],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Pan off\"\n        },\n        {\n          \"dmxRange\": [106, 155],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Invert Tilt on\"\n        },\n        {\n          \"dmxRange\": [156, 205],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Invert Tilt off\"\n        },\n        {\n          \"dmxRange\": [206, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset All Functions\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Flash Duration\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Pan/Tilt Macros\",\n        \"Pan/Tilt Speed\",\n        \"Settings\"\n      ]\n    },\n    {\n      \"name\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Flash Duration\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Pan/Tilt Macros\",\n        \"Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/hydrabeam-100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hydrabeam 100\",\n  \"shortName\": \"CLHB100RGBW\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"Flo Edelmann\"],\n    \"createDate\": \"2017-08-24\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLHB100RGBW/CLHB100RGBW_CAMEO_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=DqHGJd3NUJg\",\n      \"https://www.youtube.com/watch?v=5_bVB5iqG5s\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [160, 240, 100],\n    \"weight\": 1.9,\n    \"power\": 20,\n    \"DMXconnector\": \"3-pin\",\n    \"lens\": {\n      \"degreesMinMax\": [4.5, 4.5]\n    }\n  },\n  \"availableChannels\": {\n    \"Auto Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 1\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 2\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 3\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [77, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 4\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [123, 199],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Sound Sensitivity / Auto Mode Speed\": \"Auto Mode Speed\"\n          }\n        }\n      ]\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\",\n        \"helpWanted\": \"Correct direction?\"\n      }\n    },\n    \"Auto Mode Speed\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32639,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32639,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Head Speed\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [31, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [46, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [61, 75],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [76, 90],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [91, 105],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [106, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [121, 135],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"],\n          \"comment\": \"Red + White\"\n        },\n        {\n          \"dmxRange\": [136, 150],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [151, 165],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Green + White\"\n        },\n        {\n          \"dmxRange\": [166, 180],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [181, 195],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [196, 210],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Red + Green + White\"\n        },\n        {\n          \"dmxRange\": [211, 225],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Blue + White\"\n        },\n        {\n          \"dmxRange\": [226, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + White\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Auto Modes\",\n        \"Sound Sensitivity / Auto Mode Speed\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Head Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Head Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Head Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Head Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Auto Modes\",\n        \"Sound Sensitivity / Auto Mode Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/hydrabeam-300-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hydrabeam 300 RGBW\",\n  \"shortName\": \"CLHB300RGBW\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2017-07-24\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLHB300W/CLHB300_CAMEO_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.PDF\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_tO2vB15ieE\",\n      \"https://www.youtube.com/watch?v=OY2TEMiPsCY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [380, 240, 380],\n    \"weight\": 5.5,\n    \"power\": 60,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4.5, 4.5]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, \"1\",  null],\n        [\"2\",  null, \"3\" ]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 200,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Show mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 1\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [23, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 2\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 3\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [53, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 4\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 5\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [83, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 6\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [98, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 7\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 8\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 9\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [143, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 10\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [158, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 11\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [173, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 12\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [188, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 13\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [203, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 14\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [218, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 15\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 16\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Show mode speed\"\n          }\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity\": \"Sound sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Show mode speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Light control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto color change\"\n        },\n        {\n          \"dmxRange\": [31, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [46, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [61, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [76, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [91, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [106, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [121, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + White\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [136, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [151, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + White\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [166, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + White\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [181, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [196, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [211, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue + White\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [226, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + White\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Auto color change speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Master Pan\": {\n      \"fineChannelAliases\": [\"Master Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Master Tilt\": {\n      \"fineChannelAliases\": [\"Master Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Master Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Master Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Master Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Master White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Head speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Head Speed 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Sound mode / Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [210, 240],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Pan $pixelKey\": {\n      \"fineChannelAliases\": [\"Pan $pixelKey fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt $pixelKey\": {\n      \"fineChannelAliases\": [\"Tilt $pixelKey fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Head Speed $pixelKey simple\": {\n      \"name\": \"Head Speed $pixelKey\",\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Head Speed $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use Head Speed 1\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Strobe $pixelKey\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 200,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use master color dimmers\"\n        },\n        {\n          \"dmxRange\": [31, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [46, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [61, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [76, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [91, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [106, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [121, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + White\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [136, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [151, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + White\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [166, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + White\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [181, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [196, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [211, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue + White\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [226, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + White\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Mode $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 1\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 2\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 3\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [77, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 4\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Sound sensitivity $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [123, 199],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Show mode speed / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        }\n      ]\n    },\n    \"Show mode speed $pixelKey\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound sensitivity $pixelKey\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Show mode\",\n        \"Show mode speed / Sound sensitivity\",\n        \"Light control\",\n        \"Auto color change speed\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Master Pan\",\n        \"Master Tilt\",\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Show mode\",\n        \"Show mode speed / Sound sensitivity\",\n        \"Light control\",\n        \"Auto color change speed\",\n        \"Master Pan fine\",\n        \"Master Tilt fine\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Master Red\",\n        \"Master Green\",\n        \"Master Blue\",\n        \"Master White\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Pan $pixelKey\",\n            \"Tilt $pixelKey\",\n            \"Dimmer $pixelKey\"\n          ]\n        },\n        \"Head speed\"\n      ]\n    },\n    {\n      \"name\": \"26-channel\",\n      \"shortName\": \"26ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Pan $pixelKey\",\n            \"Pan $pixelKey fine\",\n            \"Tilt $pixelKey\",\n            \"Tilt $pixelKey fine\",\n            \"Head Speed $pixelKey\",\n            \"Color $pixelKey\"\n          ]\n        },\n        \"Sound mode / Reset\",\n        \"Sound sensitivity\",\n        \"Master Red\",\n        \"Master Green\",\n        \"Master Blue\",\n        \"Master White\"\n      ]\n    },\n    {\n      \"name\": \"42-channel\",\n      \"shortName\": \"42ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Pan $pixelKey\",\n            \"Pan $pixelKey fine\",\n            \"Tilt $pixelKey\",\n            \"Tilt $pixelKey fine\",\n            \"Head Speed $pixelKey simple\",\n            \"Dimmer $pixelKey\",\n            \"Strobe $pixelKey\",\n            \"Color $pixelKey\",\n            \"Mode $pixelKey\",\n            \"Show mode speed / Sound sensitivity $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/hydrabeam-400-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hydrabeam 400 RGBW\",\n  \"shortName\": \"CLHB400RGBW\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"ashmotif200\", \"Luke Nelson\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/1380290362\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/moving-lights/lighting-effects/2140/hydrabeam-400-rgbw\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=c2tkXBbGLMY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [810, 250, 130],\n    \"weight\": 7.5,\n    \"power\": 100,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4× 10W Cree RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4.5, 4.5]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"All\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Pan $pixelKey\": {\n      \"fineChannelAliases\": [\"Pan $pixelKey fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt $pixelKey\": {\n      \"fineChannelAliases\": [\"Tilt $pixelKey fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Head Speed $pixelKey simple\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Head Speed $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use Head Speed 1\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Strobe $pixelKey\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 200,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use master color dimmers\"\n        },\n        {\n          \"dmxRange\": [31, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [46, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [61, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [76, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [91, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [106, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [121, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + White\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [136, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [151, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + White\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [166, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + White\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [181, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [196, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [211, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue + White\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [226, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + White\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Show mode $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 1\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [23, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 2\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 3\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [53, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 4\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 5\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [83, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 6\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [98, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 7\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 8\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 9\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [143, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 10\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [158, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 11\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [173, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 12\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [188, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 13\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [203, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 14\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [218, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 15\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show mode 16\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Show mode speed $pixelKey\"\n          }\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control mode\",\n          \"switchChannels\": {\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\": \"Sound sensitivity $pixelKey\"\n          }\n        }\n      ]\n    },\n    \"Show mode speed $pixelKey\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound sensitivity $pixelKey\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Light control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto color change\"\n        },\n        {\n          \"dmxRange\": [31, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [46, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [61, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [76, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [91, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [106, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [121, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + White\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [136, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [151, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + White\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [166, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + White\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [181, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [196, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [211, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue + White\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [226, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + White\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Auto color change speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Head Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Sound mode / Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [210, 240],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer All\",\n        \"Strobe All\",\n        \"Show mode All\",\n        \"Show mode speed All / Sound sensitivity All\",\n        \"Light control\",\n        \"Auto color change speed\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Pan All\",\n        \"Tilt All\",\n        \"Dimmer All\",\n        \"Strobe All\",\n        \"Show mode All\",\n        \"Show mode speed All / Sound sensitivity All\",\n        \"Light control\",\n        \"Auto color change speed\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"All\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Pan $pixelKey fine\",\n            \"Tilt $pixelKey fine\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"19-channel\",\n      \"shortName\": \"19ch\",\n      \"channels\": [\n        \"Dimmer All\",\n        \"Strobe All\",\n        \"Red All\",\n        \"Green All\",\n        \"Blue All\",\n        \"White All\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Pan $pixelKey\",\n            \"Tilt $pixelKey\",\n            \"Dimmer $pixelKey\"\n          ]\n        },\n        \"Head Speed\"\n      ]\n    },\n    {\n      \"name\": \"32-channel\",\n      \"shortName\": \"32ch\",\n      \"channels\": [\n        \"Dimmer All\",\n        \"Strobe All\",\n        \"Pan 1\",\n        \"Pan 1 fine\",\n        \"Tilt 1\",\n        \"Tilt 1 fine\",\n        \"Head Speed 1 simple\",\n        \"Color 1\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"2\", \"3\", \"4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Pan $pixelKey\",\n            \"Pan $pixelKey fine\",\n            \"Tilt $pixelKey\",\n            \"Tilt $pixelKey fine\",\n            \"Head Speed $pixelKey\",\n            \"Color $pixelKey\"\n          ]\n        },\n        \"Sound mode / Reset\",\n        \"Sound sensitivity All\",\n        \"Red All\",\n        \"Green All\",\n        \"Blue All\",\n        \"White All\"\n      ]\n    },\n    {\n      \"name\": \"56-channel\",\n      \"shortName\": \"56ch\",\n      \"channels\": [\n        \"Pan 1\",\n        \"Pan 1 fine\",\n        \"Tilt 1\",\n        \"Tilt 1 fine\",\n        \"Head Speed 1 simple\",\n        \"Dimmer 1\",\n        \"Strobe 1\",\n        \"Color 1\",\n        \"Show mode 1\",\n        \"Show mode speed 1 / Sound sensitivity 1\",\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        \"White 1\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"2\", \"3\", \"4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Pan $pixelKey\",\n            \"Pan $pixelKey fine\",\n            \"Tilt $pixelKey\",\n            \"Tilt $pixelKey fine\",\n            \"Head Speed $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"Strobe $pixelKey\",\n            \"Color $pixelKey\",\n            \"Show mode $pixelKey\",\n            \"Show mode speed $pixelKey / Sound sensitivity $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/instant-air-1000-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Instant Air 1000 Pro\",\n  \"shortName\": \" CLIA1000PRO\",\n  \"categories\": [\"Fan\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-31\",\n    \"lastModifyDate\": \"2019-07-31\"\n  },\n  \"comment\": \"Wind machine\",\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLIA1000PRO/CLIA1000PRO_CAMEO_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.PDF\"\n    ],\n    \"productPage\": [\n      \"https://www.muziker.co.uk/cameo-instant-air-1000-pro\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=YYE02A0awqo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [385, 385, 515],\n    \"weight\": 10.9,\n    \"power\": 74,\n    \"DMXconnector\": \"3-pin and 5-pin\"\n  },\n  \"availableChannels\": {\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/instant-air-2000-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Instant Air 2000 Pro\",\n  \"shortName\": \"CLIA2000PRO\",\n  \"categories\": [\"Fan\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-07-31\",\n    \"lastModifyDate\": \"2019-07-31\"\n  },\n  \"comment\": \"Wind machine\",\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLIA2000PRO/CLIA2000PRO_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/rental/fog-effect-machines/wind-machines/20175/instant-air-2000-pro\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [385, 385, 515],\n    \"weight\": 8.6,\n    \"power\": 250,\n    \"DMXconnector\": \"3-pin and 5-pin\"\n  },\n  \"availableChannels\": {\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"440rpm\",\n          \"speedEnd\": \"2500rpm\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/instant-hazer-1500-t-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Instant Hazer 1500 T Pro\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\"],\n    \"createDate\": \"2022-07-19\",\n    \"lastModifyDate\": \"2022-07-19\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/928754720\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/cameo_instant_hazer_1500_t_pro.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i7703p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [415, 266, 555],\n    \"weight\": 17.9,\n    \"power\": 1500,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Haze\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutputStart\": \"weak\",\n          \"fogOutputEnd\": \"strong\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"comment\": \"Fan Speed\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2ch\",\n      \"channels\": [\n        \"Haze\",\n        \"Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/ioda-1000-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"IODA 1000 RGB\",\n  \"shortName\": \"CLLIODA1000RGB\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"benni\"],\n    \"createDate\": \"2019-08-21\",\n    \"lastModifyDate\": \"2019-08-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/-1031133774\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/lasers/show-lasers/2163/ioda-1000-rgb\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=LwszbJE4mg4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [188, 201, 210],\n    \"weight\": 6.5,\n    \"power\": 100,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"250 mW red laser (638 nm), 150 mW green DPSS laser (532nm), 600 mW blue laser (447 nm)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [10, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode: Cartoon graphics\"\n        },\n        {\n          \"dmxRange\": [60, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode: Beam graphics\"\n        },\n        {\n          \"dmxRange\": [110, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode: Beam graphics\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode: Cartoon graphics\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"DMX mode\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"helpWanted\": \"Does this mix to white or are there individual red, green and blue beams?\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Multiple color mode\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Pattern Select\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 1\"\n        },\n        {\n          \"dmxRange\": [2, 3],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 2\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 3\"\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 4\"\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 5\"\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 6\"\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 7\"\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 8\"\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 9\"\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 10\"\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 11\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 12\"\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 13\"\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 14\"\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 15\"\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 16\"\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 17\"\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 18\"\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 19\"\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 20\"\n        },\n        {\n          \"dmxRange\": [40, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 21\"\n        },\n        {\n          \"dmxRange\": [42, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 22\"\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 23\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 24\"\n        },\n        {\n          \"dmxRange\": [48, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 25\"\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 26\"\n        },\n        {\n          \"dmxRange\": [52, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 27\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 28\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 29\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 30\"\n        },\n        {\n          \"dmxRange\": [60, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 31\"\n        },\n        {\n          \"dmxRange\": [62, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 32\"\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 33\"\n        },\n        {\n          \"dmxRange\": [66, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 34\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 35\"\n        },\n        {\n          \"dmxRange\": [70, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 36\"\n        },\n        {\n          \"dmxRange\": [72, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 37\"\n        },\n        {\n          \"dmxRange\": [74, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 38\"\n        },\n        {\n          \"dmxRange\": [76, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 39\"\n        },\n        {\n          \"dmxRange\": [78, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 40\"\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 41\"\n        },\n        {\n          \"dmxRange\": [82, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 42\"\n        },\n        {\n          \"dmxRange\": [84, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 43\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 44\"\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 45\"\n        },\n        {\n          \"dmxRange\": [90, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 46\"\n        },\n        {\n          \"dmxRange\": [92, 93],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 47\"\n        },\n        {\n          \"dmxRange\": [94, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 48\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 49\"\n        },\n        {\n          \"dmxRange\": [98, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 50\"\n        },\n        {\n          \"dmxRange\": [100, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 51\"\n        },\n        {\n          \"dmxRange\": [102, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 52\"\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 53\"\n        },\n        {\n          \"dmxRange\": [106, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 54\"\n        },\n        {\n          \"dmxRange\": [108, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 55\"\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 56\"\n        },\n        {\n          \"dmxRange\": [112, 113],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 57\"\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 58\"\n        },\n        {\n          \"dmxRange\": [116, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 59\"\n        },\n        {\n          \"dmxRange\": [118, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 60\"\n        },\n        {\n          \"dmxRange\": [120, 121],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 61\"\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 62\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 63\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 64\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 65\"\n        },\n        {\n          \"dmxRange\": [130, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 66\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 67\"\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 68\"\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 69\"\n        },\n        {\n          \"dmxRange\": [138, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 70\"\n        },\n        {\n          \"dmxRange\": [140, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 71\"\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 72\"\n        },\n        {\n          \"dmxRange\": [144, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 73\"\n        },\n        {\n          \"dmxRange\": [146, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 74\"\n        },\n        {\n          \"dmxRange\": [148, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 75\"\n        },\n        {\n          \"dmxRange\": [150, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 76\"\n        },\n        {\n          \"dmxRange\": [152, 153],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 77\"\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 78\"\n        },\n        {\n          \"dmxRange\": [156, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 79\"\n        },\n        {\n          \"dmxRange\": [158, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 80\"\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 81\"\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 82\"\n        },\n        {\n          \"dmxRange\": [164, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 83\"\n        },\n        {\n          \"dmxRange\": [166, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 84\"\n        },\n        {\n          \"dmxRange\": [168, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 85\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 86\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 87\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 88\"\n        },\n        {\n          \"dmxRange\": [176, 177],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 89\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 90\"\n        },\n        {\n          \"dmxRange\": [180, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 91\"\n        },\n        {\n          \"dmxRange\": [182, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 92\"\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 93\"\n        },\n        {\n          \"dmxRange\": [186, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 94\"\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 95\"\n        },\n        {\n          \"dmxRange\": [190, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 96\"\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 97\"\n        },\n        {\n          \"dmxRange\": [194, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 98\"\n        },\n        {\n          \"dmxRange\": [196, 197],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 99\"\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 100\"\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 101\"\n        },\n        {\n          \"dmxRange\": [202, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 102\"\n        },\n        {\n          \"dmxRange\": [204, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 103\"\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 104\"\n        },\n        {\n          \"dmxRange\": [208, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 105\"\n        },\n        {\n          \"dmxRange\": [210, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 106\"\n        },\n        {\n          \"dmxRange\": [212, 213],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 107\"\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 108\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 109\"\n        },\n        {\n          \"dmxRange\": [218, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 110\"\n        },\n        {\n          \"dmxRange\": [220, 221],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 111\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 112\"\n        },\n        {\n          \"dmxRange\": [224, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 113\"\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 114\"\n        },\n        {\n          \"dmxRange\": [228, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 115\"\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 116\"\n        },\n        {\n          \"dmxRange\": [232, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 117\"\n        },\n        {\n          \"dmxRange\": [234, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 118\"\n        },\n        {\n          \"dmxRange\": [236, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 119\"\n        },\n        {\n          \"dmxRange\": [238, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 120\"\n        },\n        {\n          \"dmxRange\": [240, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 121\"\n        },\n        {\n          \"dmxRange\": [242, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 122\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 123\"\n        },\n        {\n          \"dmxRange\": [246, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 124\"\n        },\n        {\n          \"dmxRange\": [248, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 125\"\n        },\n        {\n          \"dmxRange\": [250, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 126\"\n        },\n        {\n          \"dmxRange\": [252, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 127\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 128\"\n        }\n      ]\n    },\n    \"Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rotation\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rotation pos. 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"X Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Y Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"X Axis Moving\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"left\",\n          \"horizontalAngleEnd\": \"right\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving forward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving backward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving backward 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto bidirectional moving\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Y Axis Moving\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"top\",\n          \"verticalAngleEnd\": \"bottom\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving downward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving upward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving downward 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto bidirectional moving\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Zoom\",\n          \"angleStart\": \"wide\",\n          \"angleEnd\": \"narrow\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Decreasing auto zooming\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Increasing auto zooming\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Drawing\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto drawing\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto drawing + de-drawing\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Scanning Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"With gaps\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Program\",\n        \"Color Presets\",\n        \"Pattern Select\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Program\",\n        \"Color Presets\",\n        \"Pattern Select\",\n        \"Rotation\",\n        \"X Axis Rolling\",\n        \"Y Axis Rolling\",\n        \"X Axis Moving\",\n        \"Y Axis Moving\",\n        \"Zoom\",\n        \"Drawing\",\n        \"Scanning Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/ioda-400-rgy.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"IODA 400 RGY\",\n  \"shortName\": \"CLLIODA400RGY\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-08-21\",\n    \"lastModifyDate\": \"2019-08-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/-1031133774\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=LwszbJE4mg4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [188, 201, 210],\n    \"weight\": 5.6,\n    \"power\": 75,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"300 mW red laser (637 nm), 120 mW green DPSS laser (532 nm)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [10, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode: Cartoon graphics\"\n        },\n        {\n          \"dmxRange\": [60, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode: Beam graphics\"\n        },\n        {\n          \"dmxRange\": [110, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode: Beam graphics\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode: Cartoon graphics\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"DMX mode\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGY\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffff00\"],\n          \"helpWanted\": \"Does this mix to only yellow or are there individual red, green and yellow beams?\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Multiple color mode\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Pattern Select\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 1\"\n        },\n        {\n          \"dmxRange\": [2, 3],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 2\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 3\"\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 4\"\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 5\"\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 6\"\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 7\"\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 8\"\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 9\"\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 10\"\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 11\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 12\"\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 13\"\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 14\"\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 15\"\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 16\"\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 17\"\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 18\"\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 19\"\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 20\"\n        },\n        {\n          \"dmxRange\": [40, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 21\"\n        },\n        {\n          \"dmxRange\": [42, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 22\"\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 23\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 24\"\n        },\n        {\n          \"dmxRange\": [48, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 25\"\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 26\"\n        },\n        {\n          \"dmxRange\": [52, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 27\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 28\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 29\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 30\"\n        },\n        {\n          \"dmxRange\": [60, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 31\"\n        },\n        {\n          \"dmxRange\": [62, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 32\"\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 33\"\n        },\n        {\n          \"dmxRange\": [66, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 34\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 35\"\n        },\n        {\n          \"dmxRange\": [70, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 36\"\n        },\n        {\n          \"dmxRange\": [72, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 37\"\n        },\n        {\n          \"dmxRange\": [74, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 38\"\n        },\n        {\n          \"dmxRange\": [76, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 39\"\n        },\n        {\n          \"dmxRange\": [78, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 40\"\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 41\"\n        },\n        {\n          \"dmxRange\": [82, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 42\"\n        },\n        {\n          \"dmxRange\": [84, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 43\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 44\"\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 45\"\n        },\n        {\n          \"dmxRange\": [90, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 46\"\n        },\n        {\n          \"dmxRange\": [92, 93],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 47\"\n        },\n        {\n          \"dmxRange\": [94, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 48\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 49\"\n        },\n        {\n          \"dmxRange\": [98, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 50\"\n        },\n        {\n          \"dmxRange\": [100, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 51\"\n        },\n        {\n          \"dmxRange\": [102, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 52\"\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 53\"\n        },\n        {\n          \"dmxRange\": [106, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 54\"\n        },\n        {\n          \"dmxRange\": [108, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 55\"\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 56\"\n        },\n        {\n          \"dmxRange\": [112, 113],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 57\"\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 58\"\n        },\n        {\n          \"dmxRange\": [116, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 59\"\n        },\n        {\n          \"dmxRange\": [118, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 60\"\n        },\n        {\n          \"dmxRange\": [120, 121],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 61\"\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 62\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 63\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 64\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 65\"\n        },\n        {\n          \"dmxRange\": [130, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 66\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 67\"\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 68\"\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 69\"\n        },\n        {\n          \"dmxRange\": [138, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 70\"\n        },\n        {\n          \"dmxRange\": [140, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 71\"\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 72\"\n        },\n        {\n          \"dmxRange\": [144, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 73\"\n        },\n        {\n          \"dmxRange\": [146, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 74\"\n        },\n        {\n          \"dmxRange\": [148, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 75\"\n        },\n        {\n          \"dmxRange\": [150, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 76\"\n        },\n        {\n          \"dmxRange\": [152, 153],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 77\"\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 78\"\n        },\n        {\n          \"dmxRange\": [156, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 79\"\n        },\n        {\n          \"dmxRange\": [158, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 80\"\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 81\"\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 82\"\n        },\n        {\n          \"dmxRange\": [164, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 83\"\n        },\n        {\n          \"dmxRange\": [166, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 84\"\n        },\n        {\n          \"dmxRange\": [168, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 85\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 86\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 87\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 88\"\n        },\n        {\n          \"dmxRange\": [176, 177],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 89\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 90\"\n        },\n        {\n          \"dmxRange\": [180, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 91\"\n        },\n        {\n          \"dmxRange\": [182, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 92\"\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 93\"\n        },\n        {\n          \"dmxRange\": [186, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 94\"\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 95\"\n        },\n        {\n          \"dmxRange\": [190, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 96\"\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 97\"\n        },\n        {\n          \"dmxRange\": [194, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 98\"\n        },\n        {\n          \"dmxRange\": [196, 197],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 99\"\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 100\"\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 101\"\n        },\n        {\n          \"dmxRange\": [202, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 102\"\n        },\n        {\n          \"dmxRange\": [204, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 103\"\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 104\"\n        },\n        {\n          \"dmxRange\": [208, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 105\"\n        },\n        {\n          \"dmxRange\": [210, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 106\"\n        },\n        {\n          \"dmxRange\": [212, 213],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 107\"\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 108\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 109\"\n        },\n        {\n          \"dmxRange\": [218, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 110\"\n        },\n        {\n          \"dmxRange\": [220, 221],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 111\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 112\"\n        },\n        {\n          \"dmxRange\": [224, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 113\"\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 114\"\n        },\n        {\n          \"dmxRange\": [228, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 115\"\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 116\"\n        },\n        {\n          \"dmxRange\": [232, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 117\"\n        },\n        {\n          \"dmxRange\": [234, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 118\"\n        },\n        {\n          \"dmxRange\": [236, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 119\"\n        },\n        {\n          \"dmxRange\": [238, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 120\"\n        },\n        {\n          \"dmxRange\": [240, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 121\"\n        },\n        {\n          \"dmxRange\": [242, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 122\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 123\"\n        },\n        {\n          \"dmxRange\": [246, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 124\"\n        },\n        {\n          \"dmxRange\": [248, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 125\"\n        },\n        {\n          \"dmxRange\": [250, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 126\"\n        },\n        {\n          \"dmxRange\": [252, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 127\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 128\"\n        }\n      ]\n    },\n    \"Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rotation\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rotation pos. 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"X Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Y Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"X Axis Moving\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"left\",\n          \"horizontalAngleEnd\": \"right\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving forward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving backward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving backward 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto bidirectional moving\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Y Axis Moving\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"top\",\n          \"verticalAngleEnd\": \"bottom\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving downward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving upward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving downward 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto bidirectional moving\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Zoom\",\n          \"angleStart\": \"wide\",\n          \"angleEnd\": \"narrow\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Decreasing auto zooming\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Increasing auto zooming\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Drawing\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto drawing\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto drawing + de-drawing\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Scanning Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"With gaps\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Program\",\n        \"Color Presets\",\n        \"Pattern Select\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Program\",\n        \"Color Presets\",\n        \"Pattern Select\",\n        \"Rotation\",\n        \"X Axis Rolling\",\n        \"Y Axis Rolling\",\n        \"X Axis Moving\",\n        \"Y Axis Moving\",\n        \"Zoom\",\n        \"Drawing\",\n        \"Scanning Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/ioda-600-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"IODA 600 RGB\",\n  \"shortName\": \"CLLIODA600RGB\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-08-21\",\n    \"lastModifyDate\": \"2019-08-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/-1031133774\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=LwszbJE4mg4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [188, 201, 210],\n    \"weight\": 5.8,\n    \"power\": 100,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"110 mW red laser (637 nm), 120 mW green DPSS laser (532 nm), 400 mW blue laser (447 nm)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [10, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode: Cartoon graphics\"\n        },\n        {\n          \"dmxRange\": [60, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode: Beam graphics\"\n        },\n        {\n          \"dmxRange\": [110, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode: Beam graphics\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode: Cartoon graphics\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"DMX mode\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"helpWanted\": \"Does this mix to white or are there individual red, green and blue beams?\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Multiple color mode\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Pattern Select\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 1\"\n        },\n        {\n          \"dmxRange\": [2, 3],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 2\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 3\"\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 4\"\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 5\"\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 6\"\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 7\"\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 8\"\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 9\"\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 10\"\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 11\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 12\"\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 13\"\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 14\"\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 15\"\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 16\"\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 17\"\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 18\"\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 19\"\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 20\"\n        },\n        {\n          \"dmxRange\": [40, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 21\"\n        },\n        {\n          \"dmxRange\": [42, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 22\"\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 23\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 24\"\n        },\n        {\n          \"dmxRange\": [48, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 25\"\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 26\"\n        },\n        {\n          \"dmxRange\": [52, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 27\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 28\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 29\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 30\"\n        },\n        {\n          \"dmxRange\": [60, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 31\"\n        },\n        {\n          \"dmxRange\": [62, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 32\"\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 33\"\n        },\n        {\n          \"dmxRange\": [66, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 34\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 35\"\n        },\n        {\n          \"dmxRange\": [70, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 36\"\n        },\n        {\n          \"dmxRange\": [72, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 37\"\n        },\n        {\n          \"dmxRange\": [74, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 38\"\n        },\n        {\n          \"dmxRange\": [76, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 39\"\n        },\n        {\n          \"dmxRange\": [78, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 40\"\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 41\"\n        },\n        {\n          \"dmxRange\": [82, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 42\"\n        },\n        {\n          \"dmxRange\": [84, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 43\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 44\"\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 45\"\n        },\n        {\n          \"dmxRange\": [90, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 46\"\n        },\n        {\n          \"dmxRange\": [92, 93],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 47\"\n        },\n        {\n          \"dmxRange\": [94, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 48\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 49\"\n        },\n        {\n          \"dmxRange\": [98, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 50\"\n        },\n        {\n          \"dmxRange\": [100, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 51\"\n        },\n        {\n          \"dmxRange\": [102, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 52\"\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 53\"\n        },\n        {\n          \"dmxRange\": [106, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 54\"\n        },\n        {\n          \"dmxRange\": [108, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 55\"\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 56\"\n        },\n        {\n          \"dmxRange\": [112, 113],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 57\"\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 58\"\n        },\n        {\n          \"dmxRange\": [116, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 59\"\n        },\n        {\n          \"dmxRange\": [118, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 60\"\n        },\n        {\n          \"dmxRange\": [120, 121],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 61\"\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 62\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 63\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 64\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 65\"\n        },\n        {\n          \"dmxRange\": [130, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 66\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 67\"\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 68\"\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 69\"\n        },\n        {\n          \"dmxRange\": [138, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 70\"\n        },\n        {\n          \"dmxRange\": [140, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 71\"\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 72\"\n        },\n        {\n          \"dmxRange\": [144, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 73\"\n        },\n        {\n          \"dmxRange\": [146, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 74\"\n        },\n        {\n          \"dmxRange\": [148, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 75\"\n        },\n        {\n          \"dmxRange\": [150, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 76\"\n        },\n        {\n          \"dmxRange\": [152, 153],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 77\"\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 78\"\n        },\n        {\n          \"dmxRange\": [156, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 79\"\n        },\n        {\n          \"dmxRange\": [158, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 80\"\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 81\"\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 82\"\n        },\n        {\n          \"dmxRange\": [164, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 83\"\n        },\n        {\n          \"dmxRange\": [166, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 84\"\n        },\n        {\n          \"dmxRange\": [168, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 85\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 86\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 87\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 88\"\n        },\n        {\n          \"dmxRange\": [176, 177],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 89\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 90\"\n        },\n        {\n          \"dmxRange\": [180, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 91\"\n        },\n        {\n          \"dmxRange\": [182, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 92\"\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 93\"\n        },\n        {\n          \"dmxRange\": [186, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 94\"\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 95\"\n        },\n        {\n          \"dmxRange\": [190, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 96\"\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 97\"\n        },\n        {\n          \"dmxRange\": [194, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 98\"\n        },\n        {\n          \"dmxRange\": [196, 197],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 99\"\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 100\"\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 101\"\n        },\n        {\n          \"dmxRange\": [202, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 102\"\n        },\n        {\n          \"dmxRange\": [204, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 103\"\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 104\"\n        },\n        {\n          \"dmxRange\": [208, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 105\"\n        },\n        {\n          \"dmxRange\": [210, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 106\"\n        },\n        {\n          \"dmxRange\": [212, 213],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 107\"\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 108\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 109\"\n        },\n        {\n          \"dmxRange\": [218, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 110\"\n        },\n        {\n          \"dmxRange\": [220, 221],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 111\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 112\"\n        },\n        {\n          \"dmxRange\": [224, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 113\"\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 114\"\n        },\n        {\n          \"dmxRange\": [228, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 115\"\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 116\"\n        },\n        {\n          \"dmxRange\": [232, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 117\"\n        },\n        {\n          \"dmxRange\": [234, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 118\"\n        },\n        {\n          \"dmxRange\": [236, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 119\"\n        },\n        {\n          \"dmxRange\": [238, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 120\"\n        },\n        {\n          \"dmxRange\": [240, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 121\"\n        },\n        {\n          \"dmxRange\": [242, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 122\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 123\"\n        },\n        {\n          \"dmxRange\": [246, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 124\"\n        },\n        {\n          \"dmxRange\": [248, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 125\"\n        },\n        {\n          \"dmxRange\": [250, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 126\"\n        },\n        {\n          \"dmxRange\": [252, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 127\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 128\"\n        }\n      ]\n    },\n    \"Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rotation\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rotation pos. 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"X Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Y Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bidirectional rolling\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"X Axis Moving\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"left\",\n          \"horizontalAngleEnd\": \"right\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving forward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving backward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving backward 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto bidirectional moving\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Y Axis Moving\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"top\",\n          \"verticalAngleEnd\": \"bottom\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving downward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving upward\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto moving downward 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto bidirectional moving\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Zoom\",\n          \"angleStart\": \"wide\",\n          \"angleEnd\": \"narrow\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Decreasing auto zooming\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Increasing auto zooming\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Drawing\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto drawing\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto drawing + de-drawing\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Scanning Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"With gaps\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Program\",\n        \"Color Presets\",\n        \"Pattern Select\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Program\",\n        \"Color Presets\",\n        \"Pattern Select\",\n        \"Rotation\",\n        \"X Axis Rolling\",\n        \"Y Axis Rolling\",\n        \"X Axis Moving\",\n        \"Y Axis Moving\",\n        \"Zoom\",\n        \"Drawing\",\n        \"Scanning Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/multi-fx-bar.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Multi FX Bar\",\n  \"shortName\": \"CLMFXBAR\",\n  \"categories\": [\"Stand\", \"Flower\", \"Laser\", \"Strobe\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ricardo Marques\"],\n    \"createDate\": \"2019-05-17\",\n    \"lastModifyDate\": \"2019-05-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLMFXBAR/CLMFXBAR_CAMEO_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://musicmax.eu/cameo-clmfxbar-multi-fx-bar~p20391en/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=rSG3BmGRIjo\",\n      \"https://www.youtube.com/watch?v=ISVSaI2liNA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1149, 414, 80],\n    \"weight\": 6.6,\n    \"power\": 130,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 12W RGBUV LEDs (PARs), 2× 3W RGB LEDs (derby), 4× 3W white LEDs (strobe), red laser (150mW / 650nm), green laser (50mW / 532nm)\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [           null,     \"Laser Red\",   \"Laser Green\",            null],\n        [\"Flash Light 1\", \"Flash Light 2\", \"Flash Light 3\", \"Flash Light 4\"],\n        [      \"Derby 1\",         \"Par 1\",         \"Par 2\",       \"Derby 2\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Laser\": [\"Laser Red\", \"Laser Green\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Auto Programs Pars\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [7, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 1\"\n        },\n        {\n          \"dmxRange\": [57, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 2\"\n        },\n        {\n          \"dmxRange\": [108, 158],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 3\"\n        },\n        {\n          \"dmxRange\": [159, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 4\"\n        },\n        {\n          \"dmxRange\": [209, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 5\"\n        }\n      ]\n    },\n    \"Auto Programs Derbys\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [7, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 1\"\n        },\n        {\n          \"dmxRange\": [57, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 2\"\n        },\n        {\n          \"dmxRange\": [108, 158],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 3\"\n        },\n        {\n          \"dmxRange\": [159, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 4\"\n        },\n        {\n          \"dmxRange\": [209, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 5\"\n        }\n      ]\n    },\n    \"Auto Programs Flash Lights\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [7, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 1\"\n        },\n        {\n          \"dmxRange\": [26, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 2\"\n        },\n        {\n          \"dmxRange\": [51, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 3\"\n        },\n        {\n          \"dmxRange\": [76, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 4\"\n        },\n        {\n          \"dmxRange\": [101, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 5\"\n        },\n        {\n          \"dmxRange\": [126, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 6\"\n        },\n        {\n          \"dmxRange\": [151, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 7\"\n        },\n        {\n          \"dmxRange\": [176, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 8\"\n        },\n        {\n          \"dmxRange\": [201, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 9\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 10\"\n        }\n      ]\n    },\n    \"Auto Programs Laser\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Effect\",\n          \"effectName\": \"Continuous Rotating Direction\"\n        },\n        {\n          \"dmxRange\": [7, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 1\"\n        },\n        {\n          \"dmxRange\": [47, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 2\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 3\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 4\"\n        },\n        {\n          \"dmxRange\": [141, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 5\"\n        },\n        {\n          \"dmxRange\": [181, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 6\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 1\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 2\"\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 3\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 4\"\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 5\"\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 6\"\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 7\"\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 8\"\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 9\"\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mix 10\"\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 1\"\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 2\"\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 3\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 4\"\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par 5\"\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 1\"\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 2\"\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 3\"\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 4\"\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby 5\"\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 1\"\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 2\"\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 3\"\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 4\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 5\"\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 6\"\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 7\"\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 8\"\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 9\"\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Par & Derby 10\"\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 1\"\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 2\"\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 3\"\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 4\"\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 5\"\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 6\"\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 7\"\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 8\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 9\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Flash Lights 10\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 1\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 2\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 3\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 4\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 5\"\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Laser 6\"\n        }\n      ]\n    },\n    \"Program Speed / Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"$pixelKey Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"$pixelKey Rotate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [5, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 132],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [133, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"$pixelKey Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-Channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Auto Programs\",\n        \"Program Speed / Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"5-Channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Auto Programs Pars\",\n        \"Auto Programs Derbys\",\n        \"Auto Programs Flash Lights\",\n        \"Auto Programs Laser\",\n        \"Program Speed / Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"29-Channel\",\n      \"shortName\": \"29ch\",\n      \"channels\": [\n        \"Derby 1 Red\",\n        \"Derby 1 Green\",\n        \"Derby 1 Blue\",\n        \"Derby 1 Strobe\",\n        \"Derby 1 Rotate\",\n        \"Derby 2 Red\",\n        \"Derby 2 Green\",\n        \"Derby 2 Blue\",\n        \"Derby 2 Strobe\",\n        \"Derby 2 Rotate\",\n        \"Par 1 Red\",\n        \"Par 1 Green\",\n        \"Par 1 Blue\",\n        \"Par 1 UV\",\n        \"Par 1 Strobe\",\n        \"Par 2 Red\",\n        \"Par 2 Green\",\n        \"Par 2 Blue\",\n        \"Par 2 UV\",\n        \"Par 2 Strobe\",\n        \"Laser Red Shutter\",\n        \"Laser Green Shutter\",\n        \"Laser Rotate\",\n        \"Flash Light 1 Shutter\",\n        \"Flash Light 2 Shutter\",\n        \"Flash Light 3 Shutter\",\n        \"Flash Light 4 Shutter\",\n        \"Auto Programs\",\n        \"Program Speed / Sound Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/multi-par-cob-1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Multi PAR COB 1\",\n  \"shortName\": \"CLMPARCOB1\",\n  \"categories\": [\"Stand\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Pascal Frank\"],\n    \"createDate\": \"2019-11-27\",\n    \"lastModifyDate\": \"2019-11-27\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLMPARCOB1/CLMPARCOB1_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.musikhaus-korn.de/en/cameo-multi-par-cob-1-set/pd/60366\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=LeBgnYJFcGA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1005, 258, 80],\n    \"weight\": 9,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"RGB COB LED\"\n    },\n    \"lens\": {\n      \"name\": \"Fesnel Lens\",\n      \"degreesMinMax\": [25, 50]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1+2\": [\"1\", \"2\"],\n      \"3+4\": [\"3\", \"4\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red+Green\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green+Blue\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red+Blue\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red+Green+Blue\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dream\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Meteor\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Change\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 1\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 2\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 3\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 4\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 5\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 6\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 7\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 8\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 9\",\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Speed / Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Sound / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 128],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Power Out 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"On\"\n        }\n      ]\n    },\n    \"Power Out 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"On\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Macros $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [5, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-Channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"4-Channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Color Macros 1\",\n        \"Color Macros 2\",\n        \"Color Macros 3\",\n        \"Color Macros 4\"\n      ]\n    },\n    {\n      \"name\": \"5-Channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Power Out 1\",\n        \"Power Out 2\"\n      ]\n    },\n    {\n      \"name\": \"6-Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red 1+2\",\n        \"Green 1+2\",\n        \"Blue 1+2\",\n        \"Red 3+4\",\n        \"Green 3+4\",\n        \"Blue 3+4\"\n      ]\n    },\n    {\n      \"name\": \"7-Channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Master Dimmer\",\n        \"Sound / Strobe\",\n        \"Power Out 1\",\n        \"Power Out 2\"\n      ]\n    },\n    {\n      \"name\": \"8-Channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Macros\",\n        \"Dimmer / Speed / Sensitivity\",\n        \"Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Power Out 1\",\n        \"Power Out 2\"\n      ]\n    },\n    {\n      \"name\": \"12-Channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"17-Channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Macros\",\n        \"Dimmer / Speed / Sensitivity\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Power Out 1\",\n        \"Power Out 2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/nanospot-120.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"NanoSpot 120\",\n  \"shortName\": \"CLNS120\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-08-05\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLNS120/CLNS120_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.PDF\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=zwyYO-s_3PI\",\n      \"https://www.youtube.com/watch?v=_FvgGrI6pe4&t=1m16s\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [159, 265, 147],\n    \"weight\": 2.6,\n    \"power\": 40,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12 W CREE LED\",\n      \"lumens\": 428\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Motor Running Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [22, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [33, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [44, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [55, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [66, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [77, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [88, 175],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [176, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 124],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 7,\n          \"helpWanted\": \"Which gobo can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [125, 234],\n          \"type\": \"WheelShake\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 7,\n          \"helpWanted\": \"Which gobo can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [235, 249],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"fast CW\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 29],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode show 1\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 81],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode show 2\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [82, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode show 3\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [108, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode show 4\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [134, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode show 5\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode show 6\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [186, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode show 7\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [212, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [238, 250],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sync (Head goes to mid position and blackout)\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mic Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Motor Running Speed\",\n        \"Color Wheel\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Motor Running Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Motor Running Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Program\",\n        \"Program Speed / Mic Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/outdoor-par-tri-12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Outdoor PAR Tri 12\",\n  \"shortName\": \"CLPSTTRI12IP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-02-24\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLPSTTRI12IP/CLPSTTRI12IP_CAMEO_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ln1KAzrTtl0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [203, 203, 193],\n    \"weight\": 4.25,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 911\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Master dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro Simple\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Black\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0%\",\n        \"speedEnd\": \"100%\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Macro Advanced\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 26],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [27, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [38, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [49, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [60, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Color Macro Simple\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Strobe\",\n        \"Color Macro Advanced\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macro Advanced\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/q-spot-40-cw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Q-Spot 40 CW\",\n  \"shortName\": \"CLQS40CW\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Nikita\"],\n    \"createDate\": \"2024-10-09\",\n    \"lastModifyDate\": \"2024-10-09\"\n  },\n  \"comment\": \"Available in black and white housing (WH suffix), not sold anymore.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/-1935126342\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=RzElVR8wCVA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [151, 130, 168],\n    \"weight\": 2.2,\n    \"power\": 55,\n    \"DMXconnector\": \"3-pin\",\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4.5, 25]\n    },\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 6500,\n      \"lumens\": 1829\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\",\n          \"comment\": \"Short burst with break\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter / Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/q-spot-40-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Q-Spot 40 RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"HS-Event\", \"Luke Nelson\"],\n    \"createDate\": \"2022-11-07\",\n    \"lastModifyDate\": \"2022-11-07\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/static-lighting/spotlights/16459/q-spot-40-rgbw\"\n    ],\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/694585978\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=RzElVR8wCVA\"\n    ],\n    \"other\": [\n      \"https://www.cameolight.com/en/downloads/file/id/940935430\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [151, 130, 168],\n    \"weight\": 2.75,\n    \"power\": 55,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 780\n    },\n    \"lens\": {\n      \"name\": \"Manual\",\n      \"degreesMinMax\": [4.5, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow Warm\"\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Strobe functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Strobe Break Effect\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"default\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"cold\",\n          \"colorTemperatureEnd\": \"warm\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch 1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch 2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe functions\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Color Temperature\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/root-par-6.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ROOT PAR 6\",\n  \"shortName\": \"CLROOTPAR6\",\n  \"categories\": [\"Color Changer\", \"Dimmer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Goetz\", \"JonahKr\"],\n    \"createDate\": \"2021-06-24\",\n    \"lastModifyDate\": \"2024-08-23\"\n  },\n  \"comment\": \"The DMX Delay channel is only activated in DMX modes when menu item \\\"DMX Delay\\\" is set to \\\"by DMX? Yes\\\".\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/-1174744700\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/static-lighting/blacklights/20729/root-par-6\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Y_CseMylQAQ\"\n    ],\n    \"other\": [\n      \"https://www.cameolight.com/en/downloads/file/id/61822611\",\n      \"https://www.cameolight.com/en/downloads/file/id/638981581\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [195, 133, 195],\n    \"weight\": 1.975,\n    \"power\": 58,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 1800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20.5, 20.5]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Color Preset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color off\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow warm\",\n          \"colors\": [\"#f4e98c\"]\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#e0b0ff\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#efe8d8\"]\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#f5feff\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 164],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [165, 201],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_1\"\n        },\n        {\n          \"dmxRange\": [208, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_2\"\n        },\n        {\n          \"dmxRange\": [214, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_3\"\n        },\n        {\n          \"dmxRange\": [220, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_4\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\"\n        }\n      ]\n    },\n    \"DMX Delay\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"off\",\n          \"comment\": \"No Delay\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 0.1,\n          \"parameterEnd\": 2,\n          \"comment\": \"Delay in seconds\"\n        }\n      ]\n    },\n    \"Strobe Multifunctional\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 22],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [23, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 45],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [46, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 68],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [69, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Sound control off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Chase\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Chase, Color Preset 1 is on\"\n        },\n        {\n          \"dmxRange\": [6, 26],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"durationStart\": \"10s\",\n          \"durationEnd\": \"4s\",\n          \"comment\": \"Chase of Color Presets 1 and 2\"\n        },\n        {\n          \"dmxRange\": [27, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"durationStart\": \"4s\",\n          \"durationEnd\": \"0.1s\",\n          \"comment\": \"Chase of Color Presets 1 and 2\"\n        },\n        {\n          \"dmxRange\": [128, 148],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"durationStart\": \"10s\",\n          \"durationEnd\": \"4s\",\n          \"comment\": \"Chase of Color Presets 1 and 2\"\n        },\n        {\n          \"dmxRange\": [149, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"durationStart\": \"4s\",\n          \"durationEnd\": \"0.1s\"\n        }\n      ]\n    },\n    \"Color Preset 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Off\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow warm\",\n          \"colors\": [\"#f4e98c\"]\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#e0b0ff\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#efe8d8\"]\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#f5feff\"]\n        },\n        {\n          \"dmxRange\": [126, 201],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_1\"\n        },\n        {\n          \"dmxRange\": [208, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_2\"\n        },\n        {\n          \"dmxRange\": [214, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_3\"\n        },\n        {\n          \"dmxRange\": [220, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_4\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\"\n        }\n      ]\n    },\n    \"Color Preset 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color off\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow warm\",\n          \"colors\": [\"#f4e98c\"]\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#e0b0ff\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#efe8d8\"]\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#f5feff\"]\n        },\n        {\n          \"dmxRange\": [126, 201],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_1\"\n        },\n        {\n          \"dmxRange\": [208, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_2\"\n        },\n        {\n          \"dmxRange\": [214, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_3\"\n        },\n        {\n          \"dmxRange\": [220, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"User Color_4\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\"\n        }\n      ]\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Preset\"\n      ]\n    },\n    {\n      \"name\": \"4-channel 1\",\n      \"shortName\": \"4ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe Multifunctional\",\n        \"Color Preset\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"4-channel 2\",\n      \"shortName\": \"4ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Chase\",\n        \"Color Preset 1\",\n        \"Color Preset 2\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe Multifunctional\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Preset\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"3-channel (with delay)\",\n      \"shortName\": \"D3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Preset\",\n        \"DMX Delay\"\n      ]\n    },\n    {\n      \"name\": \"5-channel 1 (with delay)\",\n      \"shortName\": \"D5ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe Multifunctional\",\n        \"Color Preset\",\n        \"Sound Control\",\n        \"DMX Delay\"\n      ]\n    },\n    {\n      \"name\": \"5-channel 2 (with delay)\",\n      \"shortName\": \"D5ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"DMX Delay\"\n      ]\n    },\n    {\n      \"name\": \"6-channel (with delay)\",\n      \"shortName\": \"D6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Chase\",\n        \"Color Preset 1\",\n        \"Color Preset 2\",\n        \"DMX Delay\"\n      ]\n    },\n    {\n      \"name\": \"7-channel (with delay)\",\n      \"shortName\": \"D7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"DMX Delay\"\n      ]\n    },\n    {\n      \"name\": \"9-channel (with delay)\",\n      \"shortName\": \"D9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"DMX Delay\"\n      ]\n    },\n    {\n      \"name\": \"12-channel (with delay)\",\n      \"shortName\": \"D12ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe Multifunctional\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Preset\",\n        \"Sound Control\",\n        \"DMX Delay\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/steam-wizard-1000.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Steam Wizard 1000\",\n  \"shortName\": \"CLSW1000\",\n  \"categories\": [\"Smoke\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-11-28\",\n    \"lastModifyDate\": \"2018-11-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLSW1000/CLSW1000_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=7itkJUl1CnM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [405, 200, 310],\n    \"weight\": 7.5,\n    \"power\": 800,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"9x 3W LEDs (3x red, 3x green, 3x blue)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutput\": \"off\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutputStart\": \"1m^3/min\",\n          \"fogOutputEnd\": \"150m^3/min\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"dark\",\n          \"brightnessEnd\": \"bright\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"],\n          \"helpWanted\": \"This fixture (in contrast to the 2000 variant) has no amber LED. Are these presets with amber correct?\"\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Green\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Blue\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Amber\",\n          \"colors\": [\"#ff0000\", \"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green-Blue\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green-Amber\",\n          \"colors\": [\"#00ff00\", \"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue-Amber\",\n          \"colors\": [\"#0000ff\", \"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Green-Blue\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Green-Amber\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Blue-Amber\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green-Blue-Amber\",\n          \"colors\": [\"#00ff00\", \"#0000ff\", \"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Green-Blue-Amber\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/steam-wizard-2000.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Steam Wizard 2000\",\n  \"shortName\": \"CLSW2000\",\n  \"categories\": [\"Smoke\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-11-28\",\n    \"lastModifyDate\": \"2018-11-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLSW1000/CLSW1000_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=EThpqfGSrxk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [455, 197, 318],\n    \"weight\": 8.3,\n    \"power\": 1200,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 10W RGBA LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutput\": \"off\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutputStart\": \"1m^3/min\",\n          \"fogOutputEnd\": \"500m^3/min\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"dark\",\n          \"brightnessEnd\": \"bright\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Green\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Blue\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Amber\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green-Blue\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green-Amber\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue-Amber\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Green-Blue\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Green-Amber\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Blue-Amber\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green-Blue-Amber\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red-Green-Blue-Amber\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/storm.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"STORM\",\n  \"shortName\": \"CLSTORM\",\n  \"categories\": [\"Flower\", \"Laser\", \"Strobe\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-03\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLSTORM/CLSTORM_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"],\n    \"video\": [\"https://www.youtube.com/watch?v=TsLDtXgVHX0\"]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 250, 170],\n    \"weight\": 4,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 3W RGBWA Derby LEDs, 8x 1W white LEDs, red & green laser\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [74, 74]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null, \"S1\",  \"D1\",   \"S2\", null, null],\n        [null, \"D8\", null,  null,   null, \"D2\", null],\n        [\"S8\", null, null,  null,   null, null, \"S3\"],\n        [\"D7\", null, null, \"Laser\", null, null, \"D3\"],\n        [\"S7\", null, null,  null,   null, null, \"S4\"],\n        [null, \"D6\", null,  null,   null, \"D4\", null],\n        [null, null, \"S6\",  \"D5\",   \"S5\", null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"White Strobe\": { \"name\": [\"^S[1-8]$\"] },\n      \"Derby\": { \"name\": [\"^D[1-8]$\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Derby Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Derby Colors\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Black\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#ff0000\"],\n          \"comment\": \"White + Red\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Amber + White\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#00ff00\"],\n          \"comment\": \"White + Green\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ffbf00\"],\n          \"comment\": \"Green + Amber\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ff0000\"],\n          \"comment\": \"Amber + Red\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffbf00\"],\n          \"comment\": \"Red + Green + Amber\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Red + Green + White\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffbf00\", \"#0000ff\"],\n          \"comment\": \"Red + Amber + Blue\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffffff\", \"#0000ff\"],\n          \"comment\": \"Red + White + Blue\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Red + Amber + White\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Amber + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Blue + Green + White\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Amber + Green + White\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ffffff\", \"#0000ff\"],\n          \"comment\": \"Amber + White + Blue\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"Red + Green + Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#00ff00\", \"#ffffff\", \"#ffbf00\"],\n          \"comment\": \"Blue + Green + White + Amber\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Red + Green + Amber + White\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#ff0000\", \"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"White + Red + Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + Amber + White\"\n        },\n        {\n          \"dmxRange\": [165, 209],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"one color\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"two colors\"\n        }\n      ]\n    },\n    \"Color Change Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"White LEDs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"LEDs off\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [50, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [190, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"All LEDs on\"\n        }\n      ]\n    },\n    \"Laser Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red laser on\"\n        },\n        {\n          \"dmxRange\": [50, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green laser on\"\n        },\n        {\n          \"dmxRange\": [90, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aa0000\", \"#00aa00\"],\n          \"comment\": \"Red & green flashing alternately\"\n        },\n        {\n          \"dmxRange\": [130, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00aa00\"],\n          \"comment\": \"Red on, green flashing\"\n        },\n        {\n          \"dmxRange\": [170, 209],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aa0000\", \"#00ff00\"],\n          \"comment\": \"Red flashing, green on\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aa0000\", \"#00aa00\"],\n          \"comment\": \"Red & green flashing\"\n        }\n      ]\n    },\n    \"Auto Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"NoFunction\",\n          \"comment\": \"DMX mode\"\n        },\n        {\n          \"dmxRange\": [25, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [40, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [55, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\"\n        },\n        {\n          \"dmxRange\": [85, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\"\n        },\n        {\n          \"dmxRange\": [100, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 6\"\n        },\n        {\n          \"dmxRange\": [115, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 7\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [145, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [175, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [205, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [220, 234],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [235, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blackout\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"$pixelKey Rotation\": {\n      \"defaultValue\": 130,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [5, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Derby Dimmer\",\n        \"Derby Colors\",\n        \"Color Change Speed\",\n        \"Derby Strobe\",\n        \"Derby Rotation\",\n        \"White LEDs\",\n        \"Laser Color\",\n        \"Laser Strobe\",\n        \"Laser Rotation\",\n        \"Auto Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/thunder-wash-100-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Thunder Wash 100 RGB\",\n  \"shortName\": \"CLTW100RGB\",\n  \"categories\": [\"Strobe\", \"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-02-24\",\n    \"lastModifyDate\": \"2020-02-21\"\n  },\n  \"comment\": \"Earlier models of this fixture don't have the 6ch2 mode, just one 6ch mode.\",\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLTW100RGB/CLTW100RGB_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=i2ECXkUrtXc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [310, 70, 70],\n    \"weight\": 1.0,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [75.0, 75.0]\n    }\n  },\n  \"availableChannels\": {\n    \"strobe1\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"strobe2\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"strobe3\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Break Effect\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Color off\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f9d716\"],\n          \"comment\": \"Yellow\",\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e0b0ff\"],\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffbf2\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2f6fe\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 192],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"512ms\"\n      }\n    },\n    \"Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"strobe1\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 1\",\n      \"shortName\": \"2ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 2\",\n      \"shortName\": \"2ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Flash Duration\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 3\",\n      \"shortName\": \"3ch3\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe3\",\n        \"Color Macros\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"6-channel 1\",\n      \"shortName\": \"6ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe3\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"6-channel 2\",\n      \"shortName\": \"6ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Flash Duration\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/thunder-wash-100-w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Thunder Wash 100 W\",\n  \"shortName\": \"CLTW100W\",\n  \"categories\": [\"Strobe\", \"Blinder\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-02-24\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLTW100W/CLTW100W_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"],\n    \"video\": [\"https://www.youtube.com/watch?v=i2ECXkUrtXc\"]\n  },\n  \"physical\": {\n    \"dimensions\": [310, 70, 70],\n    \"weight\": 1.0,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [75.0, 75.0]\n    }\n  },\n  \"availableChannels\": {\n    \"strobe1\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"strobe2\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"strobe3\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Break Effect\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"512ms\"\n      }\n    },\n    \"Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\"strobe1\"]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\"Dimmer\", \"strobe2\"]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\"Dimmer\", \"strobe2\", \"Flash Duration\"]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\"Dimmer\", \"strobe3\", \"Sound Control\"]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/thunder-wash-600-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Thunder Wash 600 RGB\",\n  \"shortName\": \"CLTW600RGB\",\n  \"categories\": [\"Strobe\", \"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-02-24\",\n    \"lastModifyDate\": \"2020-02-21\"\n  },\n  \"comment\": \"Earlier models of this fixture don't have the 6ch2 mode, just one 6ch mode.\",\n  \"links\": {\n    \"manual\": [\n      \"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLTW600RGB/CLTW600RGB_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=bAnmeHVZfe0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [335, 182, 93],\n    \"weight\": 3.25,\n    \"power\": 130,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [75.0, 75.0]\n    }\n  },\n  \"availableChannels\": {\n    \"strobe1\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"strobe2\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"strobe3\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Break Effect\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Color off\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f9d716\"],\n          \"comment\": \"Yellow\",\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e0b0ff\"],\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffbf2\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2f6fe\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 192],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"512ms\"\n      }\n    },\n    \"Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"strobe1\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 1\",\n      \"shortName\": \"2ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 2\",\n      \"shortName\": \"2ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Flash Duration\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 3\",\n      \"shortName\": \"3ch3\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe3\",\n        \"Color Macros\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"6-channel 1\",\n      \"shortName\": \"6ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe3\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"6-channel 2\",\n      \"shortName\": \"6ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Flash Duration\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/thunder-wash-600-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Thunder Wash 600 RGBW\",\n  \"shortName\": \"CLTW600RGBW\",\n  \"categories\": [\"Strobe\", \"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Paolo\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-11-26\",\n    \"lastModifyDate\": \"2020-11-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/1645193924\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/static-lighting/floodlights/20046/thunder-wash-600-rgbw\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=25oJ8szwaIg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [338, 197, 87],\n    \"weight\": 3.1,\n    \"power\": 160,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"648× 0.2W quad LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [75, 75]\n    }\n  },\n  \"availableChannels\": {\n    \"strobe1\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"strobe2\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"strobe3\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Break Effect\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Color off\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f9d716\"],\n          \"comment\": \"Yellow\",\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e0b0ff\"],\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffbf2\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2f6fe\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 192],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"1ms\",\n        \"durationEnd\": \"510ms\"\n      }\n    },\n    \"Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"strobe1\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 1\",\n      \"shortName\": \"2ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 2\",\n      \"shortName\": \"2ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Flash Duration\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"4-channel 1\",\n      \"shortName\": \"4ch1\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"4-channel 2\",\n      \"shortName\": \"4ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe3\",\n        \"Color Macros\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"7-channel 1\",\n      \"shortName\": \"7ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe3\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"7-channel 2\",\n      \"shortName\": \"7ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Flash Duration\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/thunder-wash-600-w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Thunder Wash 600 W\",\n  \"shortName\": \"CLTW600W\",\n  \"categories\": [\"Strobe\", \"Blinder\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-02-24\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"https://adamhall.s3.amazonaws.com/media/MARKEN/CAMEO/CLTW600W/CLTW600W_Cameo_Bedienungsanleitung_EN_DE_FR_ES_PL_IT.pdf\"],\n    \"video\": [\"https://www.youtube.com/watch?v=bAnmeHVZfe0\"]\n  },\n  \"physical\": {\n    \"dimensions\": [335, 182, 93],\n    \"weight\": 3.25,\n    \"power\": 130,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [75.0, 75.0]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1\", \"2\"],\n        [\"3\", \"4\"]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"strobe1\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"strobe2\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"strobe3\": {\n      \"name\": \"Strobe\",\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Break Effect\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"512ms\"\n      }\n    },\n    \"Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe Programs (alternating segments)\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"LED$pixelKey Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"strobe1\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Flash Duration\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe3\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"strobe2\",\n        \"Flash Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"LED$pixelKey Dimmer\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/ts-100-ww.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"TS 100 WW\",\n  \"shortName\": \"CLTS100WW\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Nikita\"],\n    \"createDate\": \"2024-10-09\",\n    \"lastModifyDate\": \"2024-10-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/-2008593426\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/static-lighting/theater-lights/19235/ts-100-ww\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [320, 370, 310],\n    \"weight\": 7.4,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 3100,\n      \"lumens\": 4100\n    },\n    \"lens\": {\n      \"name\": \"Fresnel\",\n      \"degreesMinMax\": [14, 38]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-shaped Dimmer Curve\"\n        }\n      ]\n    },\n    \"Device Settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 63],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Response LED\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Response Halogen\"\n        },\n        {\n          \"dmxRange\": [128, 154],\n          \"type\": \"Maintenance\",\n          \"parameter\": 650,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency\"\n        },\n        {\n          \"dmxRange\": [155, 181],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1530,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency\"\n        },\n        {\n          \"dmxRange\": [182, 208],\n          \"type\": \"Maintenance\",\n          \"parameter\": 3600,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency\"\n        },\n        {\n          \"dmxRange\": [209, 235],\n          \"type\": \"Maintenance\",\n          \"parameter\": 25,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer Curve\",\n        \"Device Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/ts-200-fc.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"TS 200 FC\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"jhuitila\", \"Nikita\"],\n    \"createDate\": \"2024-11-18\",\n    \"lastModifyDate\": \"2024-11-18\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/-204356236\",\n      \"https://www.cameolight.com/en/downloads/file/id/966404022\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/static-lighting/theater-lights/20479/ts-200-fc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [320, 370, 310],\n    \"weight\": 8,\n    \"power\": 200,\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"name\": \"Fresnell\"\n    },\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin and 5-pin\"\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"CCT\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2800K\",\n          \"colorTemperatureEnd\": \"8000K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ffffff\"],\n          \"comment\": \"affects only CCT\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"affects only CCT\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow warm\",\n          \"colors\": [\"#fee283\"]\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#e0b0ff\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colorTemperature\": \"3200K\",\n          \"colors\": [\"#fff1e0\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5600K\",\n          \"colors\": [\"#fffffb\"]\n        },\n        {\n          \"dmxRange\": [120, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colorTemperature\": \"8500K\",\n          \"colors\": [\"#f4fdff\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"12 colors\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"12 colors\"\n        }\n      ]\n    },\n    \"Color Mode Crossfade\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Maintenance\",\n          \"parameter\": 0,\n          \"comment\": \"0s\"\n        },\n        {\n          \"dmxRange\": [6, 105],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 0.1,\n          \"parameterEnd\": 10,\n          \"comment\": \"0.1-10s (0.1s Steps)\"\n        },\n        {\n          \"dmxRange\": [106, 214],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 11,\n          \"parameterEnd\": 119,\n          \"comment\": \"11-119s (1s Steps)\"\n        },\n        {\n          \"dmxRange\": [215, 244],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 120,\n          \"parameterEnd\": 290,\n          \"comment\": \"120-290s (10s Steps)\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 300,\n          \"parameterEnd\": 900,\n          \"comment\": \"300-900s (1m Steps)\"\n        }\n      ]\n    },\n    \"Device Settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 77],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [78, 79],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1.5s\",\n          \"comment\": \"Dimmer Response LED\"\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1.5s\",\n          \"comment\": \"Dimmer Response Halogen\"\n        },\n        {\n          \"dmxRange\": [82, 83],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1.5s\",\n          \"comment\": \"DTW (Redshift) on\"\n        },\n        {\n          \"dmxRange\": [84, 85],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1.5s\",\n          \"comment\": \"DTW (Redshift) off\"\n        },\n        {\n          \"dmxRange\": [86, 97],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [98, 99],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Silent fan\"\n        },\n        {\n          \"dmxRange\": [100, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Auto fan\"\n        },\n        {\n          \"dmxRange\": [102, 123],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"Maintenance\",\n          \"parameter\": 650,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency (Hz)\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1530,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency (Hz)\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Maintenance\",\n          \"parameter\": 3600,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency (Hz)\"\n        },\n        {\n          \"dmxRange\": [130, 131],\n          \"type\": \"Maintenance\",\n          \"parameter\": 12000,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency (Hz)\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"Maintenance\",\n          \"parameter\": 25000,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM Frequency (Hz)\"\n        },\n        {\n          \"dmxRange\": [134, 143],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [144, 145],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display on\"\n        },\n        {\n          \"dmxRange\": [146, 147],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display off\"\n        },\n        {\n          \"dmxRange\": [148, 167],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [168, 169],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Curve Linear\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Curve Exponential\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Curve Logarithmic\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Curve S-Curve\"\n        },\n        {\n          \"dmxRange\": [176, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2 HSI coarse\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 3 CCT coarse\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"Tint\"\n      ]\n    },\n    {\n      \"name\": \"6-channel Direct\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Lime\",\n        \"Cyan\"\n      ]\n    },\n    {\n      \"name\": \"12-channel HSI fine\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe functions\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"CCT\",\n        \"Tint\",\n        \"Color Macros\",\n        \"Color Mode Crossfade\",\n        \"Device Settings\"\n      ]\n    },\n    {\n      \"name\": \"14-channel Direct fine\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe functions\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Lime\",\n        \"Cyan\",\n        \"CCT\",\n        \"Tint\",\n        \"Color Macros\",\n        \"Color Mode Crossfade\",\n        \"Device Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/ts-60-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"TS 60 RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\", \"Luke Nelson\"],\n    \"createDate\": \"2022-10-20\",\n    \"lastModifyDate\": \"2024-09-03\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/dj-musicians/static-lighting/theater-lights/11911/ts-60-w-rgbw\",\n      \"https://www.cameolight.com/en/solutions/dj-musicians/static-lighting/theater-lights/13839/ts-60-w-rgbw-wh\"\n    ],\n    \"manual\": [\"https://www.cameolight.com/en/downloads/file/id/1201324186\"]\n  },\n  \"physical\": {\n    \"dimensions\": [145, 205, 240],\n    \"weight\": 3.6,\n    \"power\": 65,\n    \"DMXconnector\": \"3-pin\",\n    \"lens\": {\n      \"name\": \"Plano-convex\",\n      \"degreesMinMax\": [9, 41]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Colour Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow warm\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#af7cff\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#ff00f1\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#ffdfbf\"]\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#d0ffff\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\",\n          \"comment\": \"Color Jumping stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Colour 1 -> 12\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Colour 1 -> 12\"\n        }\n      ]\n    },\n    \"Colour Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"default\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"7200K\",\n          \"colorTemperatureEnd\": \"3200K\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Set Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-Curve Dimmer Curve\"\n        }\n      ]\n    },\n    \"Device Settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Response LED\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Response Halogen\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent Fan on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent Fan off\",\n          \"hold\": \"5s\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Colour Macros\",\n        \"Colour Temperature\",\n        \"Auto Program Speed\",\n        \"Sound\",\n        \"Set Dimmer Curve\",\n        \"Device Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/ts60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\",\n  \"name\": \"ts60\",\n  \"redirectTo\": \"cameo/ts-60-rgbw\",\n  \"reason\": \"FixtureRenamed\"\n}\n"
  },
  {
    "path": "fixtures/cameo/zenit-w600.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Zenit W600\",\n  \"shortName\": \"CLZW600\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2018-08-10\",\n    \"lastModifyDate\": \"2018-08-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.cameolight.com/en/downloads/file/id/2096475283\"\n    ],\n    \"productPage\": [\n      \"https://www.cameolight.com/en/solutions/rental/outdoor-lighting/outdoor-lights/18383/zenit-w600\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VyPoe5yLPRw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [463, 161, 291],\n    \"weight\": 13,\n    \"power\": 565,\n    \"DMXconnector\": \"5-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"40x 15W Cree LEDs\",\n      \"lumens\": 9283\n    },\n    \"lens\": {\n      \"degreesMinMax\": [18, 35]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Color off\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#f9d716\"],\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#e0b0ff\"]\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#fffbf2\"],\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#f2f6fe\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"name\": \"Color Temperature\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"8500K\",\n        \"colorTemperatureEnd\": \"3200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"name\": \"Color Temperature\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"7300K\",\n          \"colorTemperatureEnd\": \"3200K\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-Curve Dimmer Curve\"\n        }\n      ]\n    },\n    \"Device Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer Response LED\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer Response Halogen\"\n        },\n        {\n          \"dmxRange\": [192, 200],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fan Auto\"\n        },\n        {\n          \"dmxRange\": [201, 209],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fan Max\"\n        },\n        {\n          \"dmxRange\": [210, 218],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fan Silent\"\n        },\n        {\n          \"dmxRange\": [219, 223],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"LED Frequency 800Hz\"\n        },\n        {\n          \"dmxRange\": [224, 228],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"LED Frequency 1200Hz\"\n        },\n        {\n          \"dmxRange\": [229, 233],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"LED Frequency 2000Hz\"\n        },\n        {\n          \"dmxRange\": [234, 238],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"LED Frequency 3600Hz\"\n        },\n        {\n          \"dmxRange\": [239, 243],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"LED Frequency 12kHz\"\n        },\n        {\n          \"dmxRange\": [244, 248],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"LED Frequency 25kHz\"\n        },\n        {\n          \"dmxRange\": [249, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel White\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"3-channel Color Macro\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"4-channel RGBW\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"8-channel RGBW 16bit\",\n      \"shortName\": \"8ch1\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"8-channel RGBW+Macro\",\n      \"shortName\": \"8ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Device Settings\"\n      ]\n    },\n    {\n      \"name\": \"10-channel 8bit\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Color Temperature 2\",\n        \"Dimmer Curve\",\n        \"Device Settings\"\n      ]\n    },\n    {\n      \"name\": \"15-channel 16bit\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Color Macros\",\n        \"Color Temperature 2\",\n        \"Dimmer Curve\",\n        \"Device Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cameo/zenit-z120.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Zenit Z120\",\n  \"shortName\": \"Z120\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"EP\", \"Ken Harris\", \"Luke Nelson\"],\n    \"createDate\": \"2024-01-08\",\n    \"lastModifyDate\": \"2024-01-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.adamhall.com/shop/gr-en/downloads/file/id/864775656\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=q3aCVNj3t7M\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [230, 230, 300],\n    \"weight\": 8.3,\n    \"power\": 180,\n    \"powerConnectors\": {\n      \"powerCON TRUE1\": \"input and output\"\n    },\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"1× RGBW LED\",\n      \"lumens\": 2117\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 55]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"highlightValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7f00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e1b341\"],\n          \"comment\": \"Yellow Warm\"\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00b7ff\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7f00ff\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00a2\"],\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff70b8\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd8c2\"],\n          \"comment\": \"Warm White\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"white\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e1faff\"],\n          \"comment\": \"Cold White\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer response LED\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer response Halogen\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"reset all functions\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"7200K\",\n          \"colorTemperatureEnd\": \"3200K\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic Dimmer Curve\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-Curve Dimmer Curve\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Zoom\",\n        \"Settings\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Zoom\",\n        \"Zoom fine\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Color Temperature\",\n        \"Zoom\",\n        \"Dimmer Curve\",\n        \"Settings\"\n      ]\n    },\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Color Macros\",\n        \"Color Temperature\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Dimmer Curve\",\n        \"Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/colorband-pix-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"COLORband PiX IP\",\n  \"shortName\": \"ChvtDJCOLORbandPiXIP\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-04-15\",\n    \"lastModifyDate\": \"2019-04-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/COLORband_PiX_IP_UM_Rev2_WO-1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/colorband-pix-ip/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=3LjlTRm3gcs\",\n      \"https://www.youtube.com/watch?v=pgYgSIY2LlI&t=148\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [993, 173, 100],\n    \"weight\": 6.1,\n    \"power\": 103,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": { \"x\": [\"<=6\"] },\n      \"2/2\": { \"x\": [\">=7\"] },\n      \"1/3\": [\"1\", \"2\", \"3\", \"4\"],\n      \"2/3\": [\"5\", \"6\", \"7\", \"8\"],\n      \"3/3\": [\"9\", \"10\", \"11\", \"12\"],\n      \"1/4\": [\"1\", \"2\", \"3\"],\n      \"2/4\": [\"4\", \"5\", \"6\"],\n      \"3/4\": [\"7\", \"8\", \"9\"],\n      \"4/4\": [\"10\", \"11\", \"12\"],\n      \"1/6\": [\"1\", \"2\"],\n      \"2/6\": [\"3\", \"4\"],\n      \"3/6\": [\"5\", \"6\"],\n      \"4/6\": [\"7\", \"8\"],\n      \"5/6\": [\"9\", \"10\"],\n      \"6/6\": [\"11\", \"12\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macros\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Macros\",\n        \"Program Speed / Strobe\",\n        \"Auto Programs\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"36-channel\",\n      \"shortName\": \"36ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/colorband-pix.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"COLORband PiX\",\n  \"shortName\": \"ChvtDJCOLORbandPiX\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Colorblind Dude\"],\n    \"createDate\": \"2019-04-15\",\n    \"lastModifyDate\": \"2019-04-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/COLORband_PiX_UM_Rev6_WO-1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/colorband-pix/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=3LjlTRm3gcs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1057, 154, 64],\n    \"weight\": 4,\n    \"power\": 86,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": { \"x\": [\"<=6\"] },\n      \"2/2\": { \"x\": [\">=7\"] },\n      \"1/3\": [\"1\", \"2\", \"3\", \"4\"],\n      \"2/3\": [\"5\", \"6\", \"7\", \"8\"],\n      \"3/3\": [\"9\", \"10\", \"11\", \"12\"],\n      \"1/4\": [\"1\", \"2\", \"3\"],\n      \"2/4\": [\"4\", \"5\", \"6\"],\n      \"3/4\": [\"7\", \"8\", \"9\"],\n      \"4/4\": [\"10\", \"11\", \"12\"],\n      \"1/6\": [\"1\", \"2\"],\n      \"2/6\": [\"3\", \"4\"],\n      \"3/6\": [\"5\", \"6\"],\n      \"4/6\": [\"7\", \"8\"],\n      \"5/6\": [\"9\", \"10\"],\n      \"6/6\": [\"11\", \"12\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macros\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Strobe\": \"Program Speed\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Color Macros\",\n        \"Program Speed / Strobe\",\n        \"Auto Programs\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"36-channel\",\n      \"shortName\": \"36ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/corepar-uv-usb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"COREpar UV USB\",\n  \"shortName\": \"ChauvetCOREparUV\",\n  \"categories\": [\"Other\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-03-15\",\n    \"lastModifyDate\": \"2018-08-10\"\n  },\n  \"links\": {\n    \"manual\": [\"https://www.chauvetdj.com/wp-content/uploads/2015/12/COREpar_UV_USB_UM_Rev1_WO-1.pdf\"],\n    \"productPage\": [\"https://www.chauvetdj.com/products/corepar-uv-usb/\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=WsZ6dOvZ3R4\",\n      \"https://www.youtube.com/watch?v=P6M8rFnImjs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 253, 139],\n    \"weight\": 2.1,\n    \"power\": 65,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"70W COB LED\"\n    },\n    \"lens\": {\n      \"name\": \"Fresnel\",\n      \"degreesMinMax\": [50, 100]\n    }\n  },\n  \"availableChannels\": {\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode 2\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default dimmer speed\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"UV\",\n        \"Strobe / Program Speed / Sound Sensitivity\",\n        \"Programs\",\n        \"Dimmer\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"UV\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/dmx-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DMX-4\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"JEM\", \"Ken Harris\"],\n    \"createDate\": \"2022-03-15\",\n    \"lastModifyDate\": \"2022-03-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/DMX-4_UM_Rev3_WO-1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/dmx-4/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [210, 194, 70],\n    \"weight\": 2.2,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1+2\": [\"1\", \"2\"],\n      \"3+4\": [\"3\", \"4\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer Master\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer 1+2\",\n        \"Dimmer 3+4\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer 1\",\n        \"Dimmer 2\",\n        \"Dimmer 3\",\n        \"Dimmer 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/eve-p-100-ww.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"EVE P-100 WW\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-09-14\",\n    \"lastModifyDate\": \"2018-09-14\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2018/07/EVE_P-100_WW_UM_Rev2_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/eve-p-100-ww/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [245, 305, 220],\n    \"weight\": 3.5,\n    \"power\": 122,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"100WCOB LED\",\n      \"colorTemperature\": 3500,\n      \"lumens\": 5048\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"0–100%\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"100–0%\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"100–0–100%\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active program 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active program 2\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Dimmer Speed Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Dimmer speed set from display\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"off\",\n          \"comment\": \"Dimmer speed\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"fast\",\n          \"comment\": \"Dimmer speed\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"50%\",\n          \"comment\": \"Dimmer speed\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"slow\",\n          \"comment\": \"Dimmer speed\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe / Speed / Sensitivity\",\n        \"Auto Programs\",\n        \"Dimmer Speed Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/eve-p-130-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"EVE P-130 RGB\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-09-14\",\n    \"lastModifyDate\": \"2018-09-14\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2017/10/EVE_P-130_RGB_UM_Rev3_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/eve-p-130-rgb/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=JtAzheSvCG4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [245, 305, 220],\n    \"weight\": 3.5,\n    \"power\": 122,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"13 red LEDs, 13 green LEDs, 14 blue LEDs\",\n      \"lumens\": 1390\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"34Hz\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"0–100%\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"100–0%\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"100–0–100%\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 colors\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"18 colors\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active program 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active program 2\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Dimmer Speed Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Dimmer speed set from display\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"off\",\n          \"comment\": \"Dimmer speed\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"fast\",\n          \"comment\": \"Dimmer speed\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"50%\",\n          \"comment\": \"Dimmer speed\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"slow\",\n          \"comment\": \"Dimmer speed\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel RGB\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel DRGB\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Speed / Sensitivity\",\n        \"Dimmer Speed Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/freedom-h1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Freedom H1\",\n  \"shortName\": \"Freedom\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"JD\"],\n    \"createDate\": \"2018-11-13\",\n    \"lastModifyDate\": \"2018-11-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2018/01/Freedom_H1_UM_Rev1_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/freedom-h1-x4/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=URIuq7kCcV0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [75, 139, 97],\n    \"weight\": 0.7,\n    \"power\": 35,\n    \"bulb\": {\n      \"type\": \"1× 10W RGBAW+UV LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [21, 32]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Pink\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"What are Colors 1 to 11 (names and hex values)?\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active program\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Preset dimmer speed from display menu\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed medium\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/geyser-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Geyser RGB\",\n  \"categories\": [\"Smoke\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Alex Jacobs\"],\n    \"createDate\": \"2019-11-01\",\n    \"lastModifyDate\": \"2019-11-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/GeyserRGB_UM_Rev8_WO-1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/geyser-rgb/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=hQXFyo28Ndc\",\n      \"https://www.youtube.com/watch?v=pq10ol45HNE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [375, 250, 510],\n    \"weight\": 9.6,\n    \"power\": 1500,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"21× 3W LEDs (7× red, 7× green, 7× blue)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutput\": \"481m^3/min\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Red\"\n        }\n      ]\n    },\n    \"Green\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Green\"\n        }\n      ]\n    },\n    \"Blue\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Blue\"\n        }\n      ]\n    },\n    \"Color Mixing\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Auto Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Intensity\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Mixing\",\n        \"Auto Speed\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/gigbar-2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"GigBAR 2\",\n  \"categories\": [\"Stand\", \"Color Changer\", \"Laser\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2017-10-16\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"comment\": \"Par 1 and 2 can only mix 3 colors together at the same time.\",\n  \"links\": {\n    \"manual\": [\"https://www.chauvetdj.com/wp-content/uploads/2016/09/GigBAR_2_UM_Rev6_ML5_WO.pdf\"],\n    \"productPage\": [\"https://www.chauvetdj.com/products/gigbar-2/\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Nh8hEiiYxkQ\",\n      \"https://www.youtube.com/watch?v=mzO46xfRiBs\",\n      \"https://www.youtube.com/watch?v=WwCh6UE78hw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1185, 387, 110],\n    \"weight\": 6.6,\n    \"power\": 64,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input only\",\n      \"Hardwired\": \"output only\"\n    },\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [ null,      null,  null,      \"Laser\",  null,      null,  null     ],\n        [\"Strobe 1\", null, \"Strobe 2\",  null,   \"Strobe 3\", null, \"Strobe 4\"],\n        [\"Derby 1\",  null, \"Par 1\",     null,   \"Par 2\",    null, \"Derby 2\" ]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Derby\": [\"Derby 1\", \"Derby 2\"],\n      \"Pars / Derby\": [\"Par 1\", \"Par 2\", \"Derby 1\", \"Derby 2\"],\n      \"Strobe\": [\"Strobe 1\", \"Strobe 2\", \"Strobe 3\", \"Strobe 4\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Laser Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [40, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red on\"\n        },\n        {\n          \"dmxRange\": [80, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green on\"\n        },\n        {\n          \"dmxRange\": [120, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green on\"\n        },\n        {\n          \"dmxRange\": [160, 199],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00aa00\"],\n          \"comment\": \"Red on, Green strobe\"\n        },\n        {\n          \"dmxRange\": [200, 239],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aa0000\", \"#00ff00\"],\n          \"comment\": \"Red strobe, Green on\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aa0000\", \"#00aa00\"],\n          \"comment\": \"Red + Green alternate strobe\"\n        }\n      ]\n    },\n    \"Laser Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"LED Operation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mixed mode 1\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [120, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mixed mode 2\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mixed mode 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mixed mode 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show setting\"\n        }\n      ]\n    },\n    \"Show setting\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pars on ONLY, doing all single Par show\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Derby Lights on ONLY\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Laser on ONLY\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobes on ONLY\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Pars amd Derby Lights ONLY\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Pars and Laser ONLY\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Pars and Strobes ONLY\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Derby Lights and Laser ONLY\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Strobes and Derby Lights ONLY\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pars, Derby Lights and Laser\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pars, Derby Lights and Strobes\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pars, Laser and Strobes\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Derby Lights, Laser and Strobes\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Par effect\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Derby effect\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Laser effect\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Strobe effect\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Par + Derby\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Par + Laser\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Par + Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Derby + Laser\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Derby + Laser\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Pars, Derby Lights and Laser\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Pars, Derby and Strobes\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Pars, Laser and Strobes\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Derby Lights, Laser and Strobes\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Red\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [5, 54],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Red\",\n          \"brightness\": \"bright\"\n        },\n        {\n          \"dmxRange\": [55, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Green $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Green\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [5, 54],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Green\",\n          \"brightness\": \"bright\"\n        },\n        {\n          \"dmxRange\": [55, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"$pixelKey Movement Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [5, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"$pixelKey Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"$pixelKey Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"off\",\n          \"brightnessEnd\": \"bright\"\n        },\n        {\n          \"dmxRange\": [128, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"$pixelKey Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Single colors only\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Two colors at a time\"\n        }\n      ]\n    },\n    \"$pixelKey Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"$pixelKey Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [5, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"$pixelKey Patterns\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [50, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [190, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"White $pixelKey Dimmer\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 54],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"White\",\n          \"brightnessStart\": \"off\",\n          \"brightnessEnd\": \"bright\"\n        },\n        {\n          \"dmxRange\": [55, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"UV $pixelKey Dimmer\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"UV $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 54],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"UV\",\n          \"brightnessStart\": \"off\",\n          \"brightnessEnd\": \"bright\"\n        },\n        {\n          \"dmxRange\": [55, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"White / UV $pixelKey Speed\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"23-channel\",\n      \"shortName\": \"23ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Par 1\", \"Par 2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey UV\",\n            \"$pixelKey Shutter\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Derby 1\", \"Derby 2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Color\",\n            \"$pixelKey Strobe\",\n            \"$pixelKey Rotation\"\n          ]\n        },\n        \"Laser Color\",\n        \"Laser Strobe\",\n        \"Laser Movement Speed\",\n        \"Strobe Patterns\",\n        \"White Strobe Dimmer\",\n        \"UV Strobe Dimmer\",\n        \"White / UV Strobe Speed\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pars / Derby Red\",\n        \"Pars / Derby Green\",\n        \"Pars / Derby Blue\",\n        \"Pars / Derby UV\",\n        \"Pars / Derby Shutter\",\n        \"Derby Rotation\",\n        \"Red Laser\",\n        \"Green Laser\",\n        \"Laser Movement Speed\",\n        \"White Strobe\",\n        \"UV Strobe\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"LED Operation\",\n        \"Show setting\",\n        \"Auto Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/hurricane-1600.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hurricane 1600\",\n  \"categories\": [\"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"GM\"],\n    \"createDate\": \"2024-09-25\",\n    \"lastModifyDate\": \"2024-09-25\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/Hurricane_1600_UM_Rev2_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/hurricane-1600/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [348, 312, 253],\n    \"weight\": 6,\n    \"power\": 1580,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Fog Output\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutput\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutputStart\": \"0%\",\n          \"fogOutputEnd\": \"100%\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Fog Output\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/hurricane-haze-1dx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hurricane Haze 1DX\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"David Oleniacz\"],\n    \"createDate\": \"2023-07-11\",\n    \"lastModifyDate\": \"2023-07-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2017/01/Hurricane_Haze_1DX_UM_Rev3.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/hurricane-haze-1dx/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [150, 223, 278],\n    \"weight\": 3.3,\n    \"power\": 303,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Haze\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutput\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutputStart\": \"weak\",\n          \"fogOutputEnd\": \"strong\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1 Channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Haze\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/hurricane-haze-2d.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hurricane Haze 2D\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"Tryll\"],\n    \"createDate\": \"2022-11-19\",\n    \"lastModifyDate\": \"2022-11-19\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/Hurricane_Haze_2D_UM_Rev12_WO-1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/hurricane-haze-2d/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [267, 350, 285],\n    \"weight\": 8.5,\n    \"power\": 533,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Blower Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [6, 75],\n          \"type\": \"Speed\",\n          \"speed\": \"20%\"\n        },\n        {\n          \"dmxRange\": [76, 125],\n          \"type\": \"Speed\",\n          \"speed\": \"40%\"\n        },\n        {\n          \"dmxRange\": [126, 165],\n          \"type\": \"Speed\",\n          \"speed\": \"60%\"\n        },\n        {\n          \"dmxRange\": [166, 185],\n          \"type\": \"Speed\",\n          \"speed\": \"80%\"\n        },\n        {\n          \"dmxRange\": [186, 255],\n          \"type\": \"Speed\",\n          \"speed\": \"100%\"\n        }\n      ]\n    },\n    \"Haze Volume\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 38],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutput\": \"off\"\n        },\n        {\n          \"dmxRange\": [39, 69],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutput\": \"20%\"\n        },\n        {\n          \"dmxRange\": [70, 101],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutput\": \"40%\"\n        },\n        {\n          \"dmxRange\": [102, 132],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutput\": \"60%\"\n        },\n        {\n          \"dmxRange\": [133, 187],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutput\": \"80%\"\n        },\n        {\n          \"dmxRange\": [188, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutput\": \"100%\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2ch\",\n      \"channels\": [\n        \"Blower Speed\",\n        \"Haze Volume\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/intimidator-spot-110.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Intimidator Spot 110\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Lance Moore\", \"evan\"],\n    \"createDate\": \"2019-07-26\",\n    \"lastModifyDate\": \"2024-01-16\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2018/08/Intimidator_Spot_110_UM_Rev2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/intimidator-spot-110/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=JV7529ecHxo\"\n    ]\n  },\n  \"helpWanted\": \"Which colors does the color wheel contain? Also, are the Color Wheel and Gobo Wheel channels correct? The ShowXpress definition from the product page contains different capabilities and DMX ranges (including Split colors/gobos and Wheel Rotation). The manual mentions only simple slot selection.\",\n  \"physical\": {\n    \"dimensions\": [190, 279, 127],\n    \"weight\": 2.3,\n    \"power\": 41,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 10W cool white LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ff55ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#00aaff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"23Hz\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"23Hz\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"23Hz\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        }\n      ]\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt move on\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt move off\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on color wheel move on\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on color wheel move off\"\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on color wheel move on\"\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on color wheel move off\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active program\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Movement Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 1\"\n        },\n        {\n          \"dmxRange\": [36, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 2\"\n        },\n        {\n          \"dmxRange\": [56, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 3\"\n        },\n        {\n          \"dmxRange\": [76, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 4\"\n        },\n        {\n          \"dmxRange\": [96, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 5\"\n        },\n        {\n          \"dmxRange\": [116, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 6\"\n        },\n        {\n          \"dmxRange\": [136, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 7\"\n        },\n        {\n          \"dmxRange\": [156, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 8\"\n        },\n        {\n          \"dmxRange\": [176, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 9\"\n        },\n        {\n          \"dmxRange\": [196, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 10\"\n        },\n        {\n          \"dmxRange\": [216, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 11\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 12\"\n        }\n      ]\n    },\n    \"Movement Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Gobo Wheel\",\n        \"Function\",\n        \"Movement Macro\",\n        \"Movement Macro Speed\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Gobo Wheel\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/intimidator-spot-160.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Intimidator Spot 160\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-03-15\",\n    \"lastModifyDate\": \"2022-03-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2019/09/Intimidator_Spot_160_UM_Rev3.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/intimidator-spot-160/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=CBd1M3tfjuo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [207, 149, 308],\n    \"weight\": 4,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 32W cool white LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffa500\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lime green\",\n          \"colors\": [\"#66f83a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#16b116\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark blue\",\n          \"colors\": [\"#00008b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1\",\n          \"resource\": \"gobos/10-circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 7\",\n          \"resource\": \"gobos/biohazard\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 8\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 9\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10,\n          \"helpWanted\": \"The specs on the product website say \\\"9 + open\\\" colors, but the manual lists \\\"white + 8 + white\\\", so possibly one of the whites is different, but it doesn't say.\"\n        },\n        {\n          \"dmxRange\": [65, 189],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Are these the correct angles?\"\n        },\n        {\n          \"dmxRange\": [190, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [12, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [18, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [24, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [30, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [36, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [42, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [48, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [54, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [64, 69],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 75],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [76, 81],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [82, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 93],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [94, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [100, 105],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [106, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 117],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 76],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [77, 145],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [146, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt movement\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on color wheel movement\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt/color wheel movement\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt/gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt/color/gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [56, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan reset\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt reset\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color wheel reset\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo wheel reset\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Prism reset\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Focus reset\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Movement Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 1\"\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Control\",\n        \"Movement Macros\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/intimidator-spot-260.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Intimidator Spot 260\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Peter Chave\", \"Felix Edelmann\"],\n    \"createDate\": \"2019-08-22\",\n    \"lastModifyDate\": \"2019-08-22\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-08-22\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.2 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2018/08/Intimidator_Spot_260_UM_Rev3.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/intimidator-spot-260/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=PW1Yz53xUyk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [232, 351, 163],\n    \"weight\": 5.6,\n    \"power\": 107,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"White 75W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 17]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#fd8008\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lime Green\",\n          \"colors\": [\"#ccff66\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#20ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#21ff06\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#fc02ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff0a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#0000ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [65, 189],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Are these the correct angles?\"\n        },\n        {\n          \"dmxRange\": [190, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 119],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [120, 231],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo bounce\",\n          \"durationStart\": \"short\",\n          \"durationEnd\": \"long\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 4,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 76],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20.6Hz\"\n        },\n        {\n          \"dmxRange\": [77, 145],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [146, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt movement\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on color wheel movement\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt/color wheel movement\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt/gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt/color/gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [56, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan reset\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt reset\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color wheel reset\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo wheel reset\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Prism reset\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Focus reset\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Movement Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement macro 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active movement macro 8\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"17deg\",\n        \"angleEnd\": \"12deg\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism\",\n        \"Zoom\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Function\",\n        \"Movement Macro\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism\",\n        \"Zoom\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/kinta-x.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Kinta X\",\n  \"categories\": [\"Flower\"],\n  \"meta\": {\n    \"authors\": [\"Mikey Rowlands\"],\n    \"createDate\": \"2020-02-15\",\n    \"lastModifyDate\": \"2020-02-15\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2020-02-15\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.2)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://m.jam.ua/files/files/KintaX_UM_Rev4_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/news/kinta-x-becomes-an-led-powerhouse/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=yM4Mz510LHk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [283, 297, 264],\n    \"weight\": 2.7,\n    \"power\": 24,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3× 3W LEDs (1× red, green, blue each)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [135, 135]\n    }\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [15, 100],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode\"\n        }\n      ]\n    },\n    \"Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 85],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [86, 170],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation bounce\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Rotation\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/led-par-64-tri-b.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR 64 TRI-B\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-05-13\",\n    \"lastModifyDate\": \"2022-05-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2016/02/LED_PAR_64_Tri-B_-_UM_Rev4_WO-1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/led-par-64-tri-b/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [302, 251, 383],\n    \"weight\": 2.9,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18× 3W RGB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [22, 22]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"6Hz\",\n          \"speedEnd\": \"18Hz\"\n        }\n      ]\n    },\n    \"Operating Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3 colors\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 colors\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound triggering mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe / Effect Speed\",\n        \"Operating Mode\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/megastrobe-fx12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Megastrobe FX12\",\n  \"categories\": [\"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Tryll\", \"Luke Nelson\"],\n    \"createDate\": \"2022-11-28\",\n    \"lastModifyDate\": \"2022-11-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2016/02/MegaStrobe-_FX12_UM_Rev2_WO-1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/megastrobe-fx12/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=gEhNeplETGI\"\n    ],\n    \"other\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2016/02/MegaStrobe_FX12_QRG_Rev3_ML_WO.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"weight\": 1.9,\n    \"power\": 66,\n    \"dimensions\": [350, 171, 98],\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"LED 1\", \"LED 2\", \"LED 3\", \"LED 4\", \"LED 5\", \"LED 6\"],\n        [\"LED 7\", \"LED 8\", \"LED 9\", \"LED 10\", \"LED 11\", \"LED 12\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"1\": [\"LED 1\", \"LED 7\"],\n      \"2\": [\"LED 2\", \"LED 8\"],\n      \"3\": [\"LED 3\", \"LED 9\"],\n      \"4\": [\"LED 4\", \"LED 10\"],\n      \"5\": [\"LED 5\", \"LED 11\"],\n      \"6\": [\"LED 6\", \"LED 12\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter Basic\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"26Hz\"\n        }\n      ]\n    },\n    \"Shutter Advanced\": {\n      \"defaultValue\": 0,\n      \"name\": \"Shutter\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 32],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [33, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Asynchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 66],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"comment\": \"Asynchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [67, 83],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"comment\": \"Asynchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [84, 100],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"comment\": \"Asynchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 117],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Asynchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [118, 134],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [135, 151],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Synchronous - Pulse 1\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 168],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Synchronous - Pulse 2\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [169, 185],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"comment\": \"Synchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [186, 202],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"comment\": \"Synchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [203, 219],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"comment\": \"Synchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [220, 236],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Synchronous\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [237, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"switchChannels\": {\n            \"Shutter Speed / Sound Sensitivity\": \"Shutter Speed\"\n          }\n        }\n      ]\n    },\n    \"Shutter Speed\": {\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"26Hz\"\n      }\n    },\n    \"Program Speed Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"0%\",\n        \"soundSensitivityEnd\": \"100%\"\n      }\n    },\n    \"Shutter Speed Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"0%\",\n        \"soundSensitivityEnd\": \"100%\"\n      }\n    },\n    \"Pixels\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Pixel control\",\n        \"helpWanted\": \"What does this do in 'Pixel' mode?\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Is this slow -> fast or fast -> slow?\"\n      }\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 48],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Pixels\"\n          }\n        },\n        {\n          \"dmxRange\": [49, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 96],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [97, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [113, 128],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [129, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 6\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [145, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 7\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 176],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 8\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [177, 192],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 9\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [193, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 10\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [209, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 11\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 12\",\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Pixels / Program Speed / Sound Sensitivity\": \"Program Speed Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Shutter Effects\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"helpWanted\": \"What effects and at what values?\"\n      }\n    },\n    \"Shutter Effect Speed\": {\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Shutter Basic\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter Advanced\",\n        \"Shutter Speed / Sound Sensitivity\",\n        \"Pixels / Program Speed / Sound Sensitivity\",\n        \"Auto Programs\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelGroup\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\"Dimmer $pixelKey\"]\n        },\n        \"Shutter Effects\",\n        \"Shutter Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/motiondrape-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MotionDrape LED\",\n  \"shortName\": \"MotionDrape\",\n  \"categories\": [\"Effect\", \"Color Changer\", \"Other\"],\n  \"meta\": {\n    \"authors\": [\"Michael H Perbix\"],\n    \"createDate\": \"2020-04-17\",\n    \"lastModifyDate\": \"2020-04-17\"\n  },\n  \"comment\": \"Chauvet DJ MotionDrape LED QRG\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/MotionDrapeLED_UM_Rev9_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/motiondrape-led/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=K0w2q8dIJHg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [135, 50, 243],\n    \"weight\": 4.4,\n    \"power\": 54,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"176× LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Intensity\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Program 1-15\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Falling Star\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Diagonal Color Bands\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Pattern Chase\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inward Arrow (L-R)\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Stack\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Multi-Color Freeway\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Wave (L-R)\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Wave (R-L)\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Bar Chase (L-R)\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Bar Chase (R-L)\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Windmill\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fan\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Whirlpool\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Falling Snow\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Multi Box Frenzy\"\n        }\n      ]\n    },\n    \"Program 16-30\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Center Burst\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer Burst\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"EQ Effect\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rolling Color\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Horizontal Snow\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inner Zone\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer  Zone\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Diamond Spread\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single Diamond Squeeze\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Follow The Leader\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Crisscross\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"X-Factor\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double Diamond Squeeze\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red X-Factor\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Multi Rain\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Program 1-15\",\n        \"Program 16-30\",\n        \"Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/slimpar-pro-h-usb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SlimPAR Pro H USB\",\n  \"shortName\": \"ChauvetSlimPARProH\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-08-09\",\n    \"lastModifyDate\": \"2018-08-10\"\n  },\n  \"links\": {\n    \"manual\": [\"https://www.chauvetdj.com/wp-content/uploads/2016/01/SlimPAR_Pro_H_USB_UM_Rev2_WO-1.pdf\"],\n    \"productPage\": [\"https://www.chauvetdj.com/products/slimpar-pro-h-usb/\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_tN3k7mMEn0\",\n      \"https://www.youtube.com/watch?v=GP-Vg-KH8lE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [235, 290, 98],\n    \"weight\": 3.3,\n    \"power\": 97.5,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 1827\n    },\n    \"lens\": {\n      \"degreesMinMax\": [24, 24]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macros\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"32 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"comment\": \"6 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"comment\": \"32 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default dimmer speed\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Mode\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/slimpar-pro-qz12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SlimPAR Pro QZ12\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-01-01\",\n    \"lastModifyDate\": \"2018-08-10\"\n  },\n  \"links\": {\n    \"manual\": [\"https://www.chauvetdj.com/wp-content/uploads/2017/10/SlimPAR_Pro_QZ12_USB_UM_Rev1_WO.pdf\"],\n    \"productPage\": [\"https://www.chauvetdj.com/products/slimpar-pro-qz12-usb/\"],\n    \"video\": [\"https://www.youtube.com/watch?v=elPlzmj5CrI\"]\n  },\n  \"physical\": {\n    \"dimensions\": [234, 269, 318],\n    \"weight\": 4.6,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"12x 10W RGBA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 50]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macros\",\n          \"helpWanted\": \"Which colors can be selected here?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"29Hz\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 6\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default dimmer speed\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\",\n        \"helpWanted\": \"Is this the correct direction?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Speed\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Zoom\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/slimpar-pro-rgba.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SlimPAR Pro RGBA\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-03-24\",\n    \"lastModifyDate\": \"2022-03-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/SlimPAR_Pro_RGBA_UM_Rev5_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/slimpar-pro-rgba/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=sXaC7ZqkGy4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [256, 290, 87],\n    \"weight\": 2.8,\n    \"power\": 90,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"42× 1W RGBA LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [21, 21]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Magenta\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 1\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 2\",\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 3\",\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 4\",\n          \"colorTemperature\": \"4900K\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 5\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 6\",\n          \"colorTemperature\": \"5900K\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 7\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 8\",\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 9\",\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 10\",\n          \"colorTemperature\": \"8500K\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 11\",\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [204, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default speed\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear dimmer\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimmer 1\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimmer 2\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimmer 3\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/slimpar-pro-w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SlimPAR Pro W\",\n  \"shortName\": \"ChauvetSlimPARProW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-01-01\",\n    \"lastModifyDate\": \"2018-08-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2016/01/SlimPAR_PRO_W_USB_UM_Rev5.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/slimpar-pro-w-usb/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wV-9zR6L5sE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [253, 290, 98],\n    \"weight\": 3.2,\n    \"power\": 58,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 6W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Warm White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Cool White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color macros\",\n          \"helpWanted\": \"Which colors can be selected here?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"31Hz\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto fade transition\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto snap transition (3-color)\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto snap transition (7-color)\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode (3-color)\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode (7-color)\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default dimmer speed\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Warm White\",\n        \"Cool White\",\n        \"Amber\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Warm White\",\n        \"Cool White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Warm White\",\n        \"Cool White\",\n        \"Amber\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/slimpar-q12-bt.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SlimPAR Q12 BT\",\n  \"shortName\": \"ChauvetSlimPARQ12BT\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-03-28\",\n    \"lastModifyDate\": \"2018-08-10\"\n  },\n  \"links\": {\n    \"manual\": [\"https://www.chauvetdj.com/wp-content/uploads/2018/03/SlimPAR_Q12_BT_UM_Rev2_WO.pdf\"],\n    \"productPage\": [\"https://www.chauvetdj.com/products/slimpar-q12-bt/\"],\n    \"video\": [\"https://www.youtube.com/watch?v=CGcSKuTsEzA\"]\n  },\n  \"physical\": {\n    \"dimensions\": [275, 74, 279],\n    \"weight\": 1.5,\n    \"power\": 48,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 3.5W RGBA LED\",\n      \"lumens\": 895\n    },\n    \"lens\": {\n      \"degreesMinMax\": [18, 35]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Auto Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [56, 106],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [107, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [158, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [209, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 250],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Strobe\",\n        \"Auto Program\",\n        \"Auto Program Speed\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/slimpar-t12-bt.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SlimPAR T12 BT\",\n  \"shortName\": \"ChauvetSlimPART12BT\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-03-27\",\n    \"lastModifyDate\": \"2018-08-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2018/03/SlimPAR_T12BT_UM_Rev4.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/slimpar-t12-bt/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=A2SgybnQo7k\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [214, 77, 264],\n    \"weight\": 1.2,\n    \"power\": 42,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 2.5W RGBA LED\",\n      \"lumens\": 1000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14, 27]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Auto Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [56, 106],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [107, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [158, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [209, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 250],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Auto Program\",\n        \"Auto Program Speed\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/slimpar-t12-usb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SlimPAR T12 USB\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\", \"Ken Harris\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-03-22\",\n    \"lastModifyDate\": \"2022-03-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/SlimPAR_T12_USB_UM_Rev1_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/slimpar-t12-usb/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Qav_XTa3I68\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [227, 84, 252],\n    \"weight\": 1.8,\n    \"power\": 39,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 3W RGB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulse 0-100%\",\n          \"comment\": \"R/G/B channels must be active\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulse 100%-0%\",\n          \"comment\": \"R/G/B channels must be active\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulse 100%-0%-100%\",\n          \"comment\": \"R/G/B channels must be active\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"RGB\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"RGBCYMW\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default Dimmer Speed Set From Menu\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed mode\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe / Speed / Sensitivity\",\n        \"Mode\",\n        \"Dimmer\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-dj/washfx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"WashFX\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Justin Hornsby\", \"Felix Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2017-11-21\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetdj.com/wp-content/uploads/2015/12/Wash_FX_UM_Rev1_WO-1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetdj.com/products/wash-fx/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VCuOFK6Vr9k\",\n      \"https://www.youtube.com/watch?v=YYqyuCCxH7w\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [215, 255, 180],\n    \"weight\": 2.2,\n    \"power\": 75,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input only\",\n      \"Hardwired\": \"output only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [90, 90]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"4\", \"5\", \"6\"],\n        [\"3\", \"2\", \"1\"]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Auto Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 1\"\n        },\n        {\n          \"dmxRange\": [21, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 2\"\n        },\n        {\n          \"dmxRange\": [36, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 3\"\n        },\n        {\n          \"dmxRange\": [51, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 4\"\n        },\n        {\n          \"dmxRange\": [66, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 5\"\n        },\n        {\n          \"dmxRange\": [81, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 6\"\n        },\n        {\n          \"dmxRange\": [96, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 7\"\n        },\n        {\n          \"dmxRange\": [111, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 8\"\n        },\n        {\n          \"dmxRange\": [126, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 9\"\n        },\n        {\n          \"dmxRange\": [141, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 10\"\n        },\n        {\n          \"dmxRange\": [156, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 11\"\n        },\n        {\n          \"dmxRange\": [171, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 12\"\n        },\n        {\n          \"dmxRange\": [186, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 13\"\n        },\n        {\n          \"dmxRange\": [201, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 14\"\n        },\n        {\n          \"dmxRange\": [216, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 15\"\n        },\n        {\n          \"dmxRange\": [231, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 16\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Auto or Sound Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Program\"\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Auto Program\",\n        \"Auto Program Speed\",\n        \"Auto or Sound Program\"\n      ]\n    },\n    {\n      \"name\": \"23ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Auto Program\",\n        \"Auto Program Speed\",\n        \"Strobe\",\n        \"Auto or Sound Program\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-professional/colorado-1-solo.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"COLORado 1 Solo\",\n  \"shortName\": \"Solo 1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Da Graca Neves Eric\", \"Ken Harris\"],\n    \"createDate\": \"2022-04-19\",\n    \"lastModifyDate\": \"2024-10-09\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.chauvetprofessional.com/products/colorado-1-solo/\"\n    ],\n    \"manual\": [\n      \"https://www.chauvetprofessional.com/wp-content/uploads//2018/01/COLORado_1_Solo_UM_Rev8.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=0hqRufKRupk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [242, 176, 346],\n    \"weight\": 5.4,\n    \"power\": 65,\n    \"DMXconnector\": \"5-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 780\n    },\n    \"lens\": {\n      \"name\": \"Zoom\",\n      \"degreesMinMax\": [4, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": \"0%\",\n      \"highlightValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": \"0%\",\n      \"highlightValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": \"0%\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full White\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 1\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 2\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 3\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 4\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 5\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 6\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 7\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White  8\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 9\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 10\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 11\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 12\"\n        }\n      ]\n    },\n    \"White Color Macros\": {\n      \"defaultValue\": \"0%\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 1\"\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 2\"\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 3\"\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 4\"\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 5\"\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 6\"\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 7\"\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White  8\"\n        },\n        {\n          \"dmxRange\": [171, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 9\"\n        },\n        {\n          \"dmxRange\": [191, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 10\"\n        },\n        {\n          \"dmxRange\": [211, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 11\"\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 12\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [110, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Lightning\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": \"0%\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 40],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 1\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 2\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 3\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 4\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 5\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 6\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 7\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 8\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 9\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Auto 10\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Red\",\n            \"Green / Fade Duration\": \"Green\",\n            \"Dimmer fine / Step Duration\": \"Dimmer fine\",\n            \"Red / Fade Duration\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 1\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 2\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 3\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 4\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 5\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 6\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 7\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 8\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 9\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Custom 10\",\n          \"switchChannels\": {\n            \"Red / Step Duration\": \"Step Duration\",\n            \"Green / Fade Duration\": \"Fade Duration\",\n            \"Dimmer fine / Step Duration\": \"Step Duration\",\n            \"Red / Fade Duration\": \"Fade Duration\"\n          }\n        }\n      ]\n    },\n    \"Auto Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"comment\": \"Only when using Auto 1-10\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": \"0%\",\n      \"highlightValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"4deg\",\n        \"angleEnd\": \"40deg\"\n      }\n    },\n    \"Zoom Control\": {\n      \"name\": \"Zoom\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 200],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Zoom\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Preset Dimmer From Display Menu\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer\"\n        },\n        {\n          \"dmxRange\": [30, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"NonLinear Dimmer Curve 1 (Fastest)\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"NonLinear Dimmer Curve 2\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"NonLinear Dimmer Curve 3\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"NonLinear Dimmer Curve 4 (Slowest)\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Step Duration\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"long\",\n        \"durationEnd\": \"short\",\n        \"helpWanted\": \"Is this the correct direction (same as menu control)?\"\n      }\n    },\n    \"Fade Duration\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"long\",\n        \"durationEnd\": \"short\",\n        \"helpWanted\": \"Is this the correct direction (same as menu control)?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Std. Y\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine / Step Duration\",\n        \"Red / Fade Duration\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Programs\",\n        \"Auto Speed\",\n        \"Zoom\",\n        \"Zoom Control\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"TR16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine / Step Duration\",\n        \"Red / Fade Duration\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Programs\",\n        \"Auto Speed\",\n        \"Zoom\",\n        \"Zoom Control\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"TOUR\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red / Step Duration\",\n        \"Green / Fade Duration\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Programs\",\n        \"Auto Speed\",\n        \"Zoom\",\n        \"Zoom Control\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"SSP\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Zoom\",\n        \"Zoom Control\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"HSIC\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"White Color Macros\",\n        \"Strobe\",\n        \"Zoom\",\n        \"Zoom Control\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-professional/colordash-batten-quad-6.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"COLORdash Batten-Quad 6\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-09-14\",\n    \"lastModifyDate\": \"2018-09-14\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetprofessional.com/wp-content/uploads/2015/07/COLORDash_Batten-Quad_6_UM_Rev7_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetprofessional.com/products/colordash-batten-quad-6/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vZglF_D2c24\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [494.5, 82, 154],\n    \"weight\": 2.3,\n    \"power\": 96,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"6x 5W Quad LEDs\",\n      \"lumens\": 674\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"6\", \"5\", \"4\", \"3\", \"2\", \"1\"]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color Macros + White Balance\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 100%, Green 0…100%, Blue 0%\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 100…0%, Green 100%, Blue 0%\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 0%, Green 100%, Blue 0…100%\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 0%, Green 100…0%, Blue 100%\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 0…100%, Green 0%, Blue 100%\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 100%, Green 0%, Blue 100…0%\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 100%, Green 0…100%, Blue 0…100%\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 100…0%, Green 100…0%, Blue 100%\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red 100%, Green 100%, Blue 100%, Amber 100%\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 1\",\n          \"helpWanted\": \"Which white tones can be selected here? Are they from cold white to warm white or similar?\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 2\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 3\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 4\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 5\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 6\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 7\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 8\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 9\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 10\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 11\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\"\n        },\n        {\n          \"dmxRange\": [204, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 5\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Dimmer curve set from display menu\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear dimmer\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimmer curve 1 (fastest)\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimmer curve 2\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimmer curve 3 (slowest)\"\n        }\n      ]\n    },\n    \"Auto Programs 2\": {\n      \"name\": \"Auto Programs\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\"\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\"\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\"\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\"\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 5\"\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 6\"\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 7\"\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 8\"\n        },\n        {\n          \"dmxRange\": [171, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 9\"\n        },\n        {\n          \"dmxRange\": [191, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 10\"\n        },\n        {\n          \"dmxRange\": [211, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 11\"\n        },\n        {\n          \"dmxRange\": [231, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 12\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random auto program\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Strobe\",\n        \"Color Macros + White Balance\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"24-channel\",\n      \"shortName\": \"24ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"28-channel\",\n      \"shortName\": \"28ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        },\n        \"Auto Programs 2\",\n        \"Program Speed\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-professional/colordash-s-par-1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"COLORdash S-Par 1\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Max Jöhnk\", \"Ryan Goodwin\"],\n    \"createDate\": \"2023-10-18\",\n    \"lastModifyDate\": \"2023-10-18\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetprofessional.com/wp-content/uploads/2015/07/COLORdash_S-Par_1_UM_Rev1_WO1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetprofessional.com/products/colordash-s-par-1/\"\n    ],\n    \"other\": [\n      \"https://www.chauvetprofessional.com/news/chauvet-professionals-ip65-colordash-s-par-1-rgba-wash-breaks-the-led-color-separation-barrier/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [231, 169, 313],\n    \"weight\": 6.5,\n    \"power\": 65,\n    \"DMXconnector\": \"5-pin\",\n    \"powerConnectors\": {\n      \"powerCON TRUE1\": \"input and output\"\n    },\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [22, 42]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Macro + White Balance\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA white\",\n          \"colors\": [\"#ffebd9\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 1\",\n          \"colors\": [\"#ffffff\"],\n          \"helpWanted\": \"What is the difference between all the white presets?\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 2\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 3\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 4\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 5\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 6\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 7\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 8\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 9\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 10\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 11\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 250],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"warm\",\n          \"colorTemperatureEnd\": \"cold\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [61, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [111, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [161, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        }\n      ]\n    },\n    \"Auto Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Preset dimmer speed from display menu\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Dimmer\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimming curve 1 (fastest)\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimming curve 2\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Nonlinear dimming curve 3 (slowest)\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Strobe\",\n        \"Color Macro + White Balance\",\n        \"Color Temperature\",\n        \"Auto Programs\",\n        \"Auto Speed\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-professional/ovation-f-915vw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Ovation F-915VW\",\n  \"shortName\": \"ChauvetOvationF915VW\",\n  \"categories\": [\"Color Changer\", \"Dimmer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Nicolas\"],\n    \"createDate\": \"2019-04-06\",\n    \"lastModifyDate\": \"2019-04-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetprofessional.com/wp-content/uploads/2017/11/Ovation_F-915VW_UM_Rev1_WO.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetprofessional.com/products/ovation-f-915vw/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=bSrkOqNl9SI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [320, 275, 569.44],\n    \"weight\": 8.5,\n    \"power\": 223,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"89× 3W LED (6× red, 15× orange-red, 8× green, 12× blue, 16× royal blue, 32× lime)\",\n      \"lumens\": 6792\n    },\n    \"lens\": {\n      \"name\": \"Fresnel\",\n      \"degreesMinMax\": [17, 54]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Orange\": {\n      \"fineChannelAliases\": [\"Orange fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Royal Blue\": {\n      \"fineChannelAliases\": [\"Royal Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Lime\": {\n      \"fineChannelAliases\": [\"Lime fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"27Hz\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 244],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2800K\",\n          \"colorTemperatureEnd\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"-25° … 25°\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"17deg\",\n        \"angleEnd\": \"54deg\"\n      }\n    },\n    \"Dimmer Speed Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer speed mode off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer speed mode 1\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer speed mode 2\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer speed mode 3\"\n        }\n      ]\n    },\n    \"Motor Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 200],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Motor Reset\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Orange\",\n        \"Orange fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Royal Blue\",\n        \"Royal Blue fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Lime\",\n        \"Lime fine\",\n        \"Strobe\",\n        \"Color Temperature\",\n        \"Hue\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Orange\",\n        \"Orange fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Royal Blue\",\n        \"Royal Blue fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Lime\",\n        \"Lime fine\",\n        \"Strobe\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Orange\",\n        \"Green\",\n        \"Royal Blue\",\n        \"Blue\",\n        \"Lime\",\n        \"Strobe\",\n        \"Color Temperature\",\n        \"Hue\",\n        \"Dimmer Speed Mode\",\n        \"Zoom\",\n        \"Motor Reset\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Orange\",\n        \"Green\",\n        \"Royal Blue\",\n        \"Blue\",\n        \"Lime\",\n        \"Strobe\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Orange\",\n        \"Green\",\n        \"Royal Blue\",\n        \"Blue\",\n        \"Lime\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Hue\",\n        \"Zoom\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Hue\",\n        \"Zoom\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-professional/rogue-r1-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Rogue R1 Wash\",\n  \"shortName\": \"rogue-r1-wash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-03-07\",\n    \"lastModifyDate\": \"2024-01-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetprofessional.com/wp-content/uploads/2015/06/ROGUE_R1_Wash_UM_Rev2_WO1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetprofessional.com/products/rogue-r1-wash/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=YWUMAocTR_w\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [265, 354, 187],\n    \"weight\": 5.9,\n    \"power\": 161,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"7× 15W RGBW LEDs\",\n      \"lumens\": 2300\n    },\n    \"lens\": {\n      \"degreesMinMax\": [8, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [25, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"20Hz\",\n          \"speedEnd\": \"0Hz\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"randomTiming\": true,\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"randomTiming\": true,\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [230, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Color 1 = White\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffeb34\"],\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d68630\"],\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff002c\"],\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff3b71\"],\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8adb\"],\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e2afe2\"],\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2801ff\"],\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#004eff\"],\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00c7ff\"],\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffea\"],\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#95f6ff\"],\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#89ffe3\"],\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d5dcde\"],\n          \"comment\": \"Color 15\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbe8af\"],\n          \"comment\": \"Color 16\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cdffc7\"],\n          \"comment\": \"Color 17\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#73ffa5\"],\n          \"comment\": \"Color 18\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#06ff8f\"],\n          \"comment\": \"Color 19\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff5e\"],\n          \"comment\": \"Color 20\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#1dff00\"],\n          \"comment\": \"Color 21\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#20df00\"],\n          \"comment\": \"Color 22\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4bff00\"],\n          \"comment\": \"Color 23\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50e800\"],\n          \"comment\": \"Color 24\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6ce200\"],\n          \"comment\": \"Color 25\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#91c200\"],\n          \"comment\": \"Color 26\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d2ff00\"],\n          \"comment\": \"Color 27\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e1e800\"],\n          \"comment\": \"Color 28\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#17d700\"],\n          \"comment\": \"Color 29\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f7d600\"],\n          \"comment\": \"Color 30\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa300\"],\n          \"comment\": \"Color 31\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9800\"],\n          \"comment\": \"Color 32\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6c00\"],\n          \"comment\": \"Color 33\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Color 34 = Full White\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Closed\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [180, 201],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [208, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Closed\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [235, 249],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Closed\",\n          \"colors\": [\"#000000\"]\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"8deg\",\n        \"angleEnd\": \"30deg\"\n      }\n    },\n    \"Movement Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 9\"\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 10\"\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 11\"\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 12\"\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 13\"\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 14\"\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 16\"\n        }\n      ]\n    },\n    \"Movement Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Blackout during pan/tilt\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan reset\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Tilt reset\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Zoom reset\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"All reset\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan/Tilt movement reverse\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan movement reverse\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Tilt movement reverse\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Disable Pan movement reverse\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Disable Tilt movement reverse\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Disable Pan/Tilt movement reverse\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Eco fan\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Full fan\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Auto fan\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fast dimmer curve\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Smooth dimmer curve\"\n        },\n        {\n          \"dmxRange\": [145, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"21-channel\",\n      \"shortName\": \"21ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Color Presets\",\n        \"Zoom\",\n        \"Movement Macros\",\n        \"Movement Macro Speed\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"19-channel\",\n      \"shortName\": \"19ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Color Presets\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Presets\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Presets\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-professional/rogue-r2-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Rogue R2 Wash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Ken Harris\"],\n    \"createDate\": \"2018-12-10\",\n    \"lastModifyDate\": \"2022-03-18\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.chauvetprofessional.com/wp-content/uploads/2015/06/ROGUE_R2_Wash_UM_Rev4_WO2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.chauvetprofessional.com/products/rogue-r2-wash/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=YWUMAocTR_w\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [306, 398, 218],\n    \"weight\": 9.25,\n    \"power\": 339,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"19× 15W LED\",\n      \"lumens\": 8500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [8, 30]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null, null, \"1c\", null, \"1d\", null, null, null],\n        [null, \"1b\", null, null, null, null, null, \"1e\", null],\n        [null, null, null, null, \"2b\", null, null, null, null],\n        [\"1a\", null, \"2a\", null, null, null, \"2c\", null, \"1f\"],\n        [null, null, null, null,  \"3\", null, null, null, null],\n        [\"5a\", null, \"4a\", null, null, null, \"4c\", null, \"5f\"],\n        [null, null, null, null, \"4b\", null, null, null, null],\n        [null, \"5b\", null, null, null, null, null, \"5e\", null],\n        [null, null, null, \"5c\", null, \"5d\", null, null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Zone 1\": [\"1a\", \"1b\", \"1c\", \"1d\", \"1e\", \"1f\"],\n      \"Zone 2\": [\"2a\", \"2b\", \"2c\"],\n      \"Zone 3\": [\"3\"],\n      \"Zone 4\": [\"4a\", \"4b\", \"4c\"],\n      \"Zone 5\": [\"5a\", \"5b\", \"5c\", \"5d\", \"5e\", \"5f\"],\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [25, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"20Hz\",\n          \"speedEnd\": \"0Hz\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"helpWanted\": \"Are all these shutter ranges fast...slow like the Rogue R1 Wash?\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [230, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Color 1 = White\",\n          \"helpWanted\": \"Are these the correct colors?\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffeb34\"],\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d68630\"],\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff002c\"],\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff3b71\"],\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8adb\"],\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e2afe2\"],\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2801ff\"],\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#004eff\"],\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00c7ff\"],\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffea\"],\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#95f6ff\"],\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#89ffe3\"],\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d5dcde\"],\n          \"comment\": \"Color 15\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbe8af\"],\n          \"comment\": \"Color 16\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cdffc7\"],\n          \"comment\": \"Color 17\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#73ffa5\"],\n          \"comment\": \"Color 18\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#06ff8f\"],\n          \"comment\": \"Color 19\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff5e\"],\n          \"comment\": \"Color 20\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#1dff00\"],\n          \"comment\": \"Color 21\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#20df00\"],\n          \"comment\": \"Color 22\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4bff00\"],\n          \"comment\": \"Color 23\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50e800\"],\n          \"comment\": \"Color 24\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6ce200\"],\n          \"comment\": \"Color 25\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#91c200\"],\n          \"comment\": \"Color 26\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d2ff00\"],\n          \"comment\": \"Color 27\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e1e800\"],\n          \"comment\": \"Color 28\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#17d700\"],\n          \"comment\": \"Color 29\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f7d600\"],\n          \"comment\": \"Color 30\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa300\"],\n          \"comment\": \"Color 31\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9800\"],\n          \"comment\": \"Color 32\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6c00\"],\n          \"comment\": \"Color 33\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Color 34 = Full White\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Closed\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [180, 201],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [208, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Closed\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [235, 249],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Closed\",\n          \"colors\": [\"#000000\"]\n        }\n      ]\n    },\n    \"Zone Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 3, 4, 5\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 2, 3, 4, 5\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 3, 4, 5\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 4, 5\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 5\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 3\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 3, 4\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 3, 4, 5\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 2\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 3\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 4\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 5\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 2, 3\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 3, 4\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 4, 5\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 5\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 3\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 2, 3, 4\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 3, 4, 5\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 4, 5\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 5\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 3, 4\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 2, 3, 4, 5\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 3, 4, 5\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 4, 5\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 3, 5\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zone 1, 2, 3, 4, 5\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 1\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 2\"\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 3\"\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 4\"\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 5\"\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 6\"\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 7\"\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 8\"\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 9\"\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 10\"\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 11\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 12\"\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 13\"\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 14\"\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 15\"\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 16\"\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 17\"\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 18\"\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 19\"\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 20\"\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 21\"\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 22\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 23\"\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring macro 24\"\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 1\"\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 2\"\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 3\"\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 4\"\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 5\"\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 6\"\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 7\"\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 8\"\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 9\"\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 10\"\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 11\"\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 12\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 13\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 14\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 15\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 16\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 17\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 18\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 19\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 20\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 21\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 22\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 23\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color ring macro 24\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Movement Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 9\"\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 10\"\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 11\"\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 12\"\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 13\"\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 14\"\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 16\"\n        }\n      ]\n    },\n    \"Movement Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"12deg\",\n        \"angleEnd\": \"49deg\"\n      }\n    },\n    \"Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during pan/tilt\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan reset\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Tilt reset\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Zoom reset\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"All reset\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan/Tilt movement reverse\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan movement reverse\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Tilt movement reverse\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Disable Pan movement reverse\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Disable Tilt movement reverse\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Disable Pan/Tilt movement reverse\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Eco fan\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Full fan\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Auto fan\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fast dimmer curve\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Smooth dimmer curve\"\n        },\n        {\n          \"dmxRange\": [145, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"fineChannelAliases\": [\"Red $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"fineChannelAliases\": [\"Green $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"fineChannelAliases\": [\"Blue $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"fineChannelAliases\": [\"White $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"56-channel\",\n      \"shortName\": \"56ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Zone 1\", \"Zone 2\", \"Zone 3\", \"Zone 4\", \"Zone 5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Red $pixelKey fine\",\n            \"Green $pixelKey\",\n            \"Green $pixelKey fine\",\n            \"Blue $pixelKey\",\n            \"Blue $pixelKey fine\",\n            \"White $pixelKey\",\n            \"White $pixelKey fine\"\n          ]\n        },\n        \"Color\",\n        \"Zone Selection\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Movement Macros\",\n        \"Movement Macro Speed\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"54-channel\",\n      \"shortName\": \"54ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Zone 1\", \"Zone 2\", \"Zone 3\", \"Zone 4\", \"Zone 5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Red $pixelKey fine\",\n            \"Green $pixelKey\",\n            \"Green $pixelKey fine\",\n            \"Blue $pixelKey\",\n            \"Blue $pixelKey fine\",\n            \"White $pixelKey\",\n            \"White $pixelKey fine\"\n          ]\n        },\n        \"Color\",\n        \"Zone Selection\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"54-channel MS\",\n      \"shortName\": \"54ch-MS\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Color\",\n        \"Zone Selection\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Zoom\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Zone 1\", \"Zone 2\", \"Zone 3\", \"Zone 4\", \"Zone 5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Red $pixelKey fine\",\n            \"Green $pixelKey\",\n            \"Green $pixelKey fine\",\n            \"Blue $pixelKey\",\n            \"Blue $pixelKey fine\",\n            \"White $pixelKey\",\n            \"White $pixelKey fine\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"33-channel\",\n      \"shortName\": \"33ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Zone 1\", \"Zone 2\", \"Zone 3\", \"Zone 4\", \"Zone 5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Color\",\n        \"Zone Selection\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"33-channel MS\",\n      \"shortName\": \"33ch-MS\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Color\",\n        \"Zone Selection\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Zoom\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Zone 1\", \"Zone 2\", \"Zone 3\", \"Zone 4\", \"Zone 5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"22-channel\",\n      \"shortName\": \"22ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Red Master\",\n        \"Red Master fine\",\n        \"Green Master\",\n        \"Green Master fine\",\n        \"Blue Master\",\n        \"Blue Master fine\",\n        \"White Master\",\n        \"White Master fine\",\n        \"Color\",\n        \"Zone Selection\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Color\",\n        \"Zone Selection\",\n        \"Programs\",\n        \"Program Speed\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Color\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chauvet-professional/vesuvio-rgba.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Vesuvio RGBA\",\n  \"categories\": [\"Smoke\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Beerady\", \"Luke Nelson\"],\n    \"createDate\": \"2022-10-18\",\n    \"lastModifyDate\": \"2022-10-18\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://web.archive.org/web/20160421173724/http://www.chauvetprofessional.com/products/vesuvio-rgba/\"\n    ],\n    \"manual\": [\n      \"https://www.chauvetprofessional.com/wp-content/uploads/2015/06/Vesuvio-RGBA_UM_Rev4_WO.pdf\"\n    ],\n    \"video\": [\"https://www.youtube.com/watch?v=HH5G92l4USw\"]\n  },\n  \"rdm\": {\n    \"modelId\": 37266,\n    \"softwareVersion\": \"2016\"\n  },\n  \"physical\": {\n    \"dimensions\": [336, 488, 231],\n    \"weight\": 13.6,\n    \"power\": 1590,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Fog\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the light constantly on or off?\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Blue\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [13, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [17, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [21, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [25, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green/Blue dim to bright\",\n          \"helpWanted\": \"Why are some capabilities duplicated? What is the actual color at each DMX value?\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [29, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [33, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [37, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [41, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [45, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [53, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [57, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green\"\n        },\n        {\n          \"dmxRange\": [61, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [65, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [69, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [72, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [73, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [76, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [77, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [80, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [81, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [89, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [92, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [101, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [105, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [109, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue\"\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [113, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [117, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [121, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [125, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [133, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [137, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [141, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [144, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [145, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [148, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [149, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [153, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [157, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [165, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [168, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [169, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [172, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [176, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [177, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [181, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [184, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [185, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [189, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [193, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [197, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [201, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber\"\n        },\n        {\n          \"dmxRange\": [205, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [209, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [217, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [221, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [225, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [229, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [232, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [233, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [237, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [241, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [245, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red/Green/Amber/Blue dim to bright\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chroma-q/color-force-ii-12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Color Force II 12\",\n  \"shortName\": \"CHCF212RGBA\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-13\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://chroma-q.com/assets/uploads/product_downloads/56078f55536c193d0748200af69d480f.pdf\"\n    ],\n    \"productPage\": [\n      \"https://chroma-q.com/products/color-force-ii-12\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=z5E7URWnnmQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [335, 191, 165],\n    \"weight\": 5,\n    \"power\": 160,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [22, 22]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [72.7, 81.2, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"1/2\": [\"1\", \"2\"],\n      \"2/2\": [\"3\", \"4\"],\n      \"Master\": [\"1\", \"2\", \"3\", \"4\"],\n      \"Odd\": [\"1\", \"3\"],\n      \"Even\": [\"2\", \"4\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Look Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Look 1 (default Red)\",\n          \"helpWanted\": \"Are the capability ranges correct?\"\n        },\n        {\n          \"dmxRange\": [9, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Look 2 (default Pink)\"\n        },\n        {\n          \"dmxRange\": [17, 25],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8800\"],\n          \"comment\": \"Look 3 (default Orange)\"\n        },\n        {\n          \"dmxRange\": [26, 33],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbb00\"],\n          \"comment\": \"Look 4 (default Light Orange)\"\n        },\n        {\n          \"dmxRange\": [34, 42],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Look 5 (default Yellow)\"\n        },\n        {\n          \"dmxRange\": [43, 51],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff88\"],\n          \"comment\": \"Look 6 (default Light Yellow)\"\n        },\n        {\n          \"dmxRange\": [52, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Look 7 (default Green)\"\n        },\n        {\n          \"dmxRange\": [60, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffaa\"],\n          \"comment\": \"Look 8 (default Light Green)\"\n        },\n        {\n          \"dmxRange\": [68, 75],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Look 9 (default Cyan)\"\n        },\n        {\n          \"dmxRange\": [76, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffff\"],\n          \"comment\": \"Look 10 (default Light Cyan)\"\n        },\n        {\n          \"dmxRange\": [85, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Look 11 (default Blue)\"\n        },\n        {\n          \"dmxRange\": [93, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#88aaff\"],\n          \"comment\": \"Look 12 (default Light Blue)\"\n        },\n        {\n          \"dmxRange\": [101, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaa5f\"],\n          \"comment\": \"Look 13 (default 2800K White)\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"comment\": \"Look 14 (default 3200K White)\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffcea6\"],\n          \"comment\": \"Look 15 (default 4000K White)\"\n        },\n        {\n          \"dmxRange\": [126, 133],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"comment\": \"Look 16 (default 5600K White)\"\n        },\n        {\n          \"dmxRange\": [134, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 17 (default empty)\"\n        },\n        {\n          \"dmxRange\": [142, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 18 (default empty)\"\n        },\n        {\n          \"dmxRange\": [150, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 19 (default empty)\"\n        },\n        {\n          \"dmxRange\": [158, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 20 (default empty)\"\n        },\n        {\n          \"dmxRange\": [166, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 21 (default empty)\"\n        },\n        {\n          \"dmxRange\": [175, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 22 (default empty)\"\n        },\n        {\n          \"dmxRange\": [183, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 23 (default empty)\"\n        },\n        {\n          \"dmxRange\": [191, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 24 (default empty)\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 25 (default empty)\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 26 (default empty)\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 27 (default empty)\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 28 (default empty)\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 29 (default empty)\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 30 (default empty)\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 31 (default empty)\"\n        }\n      ]\n    },\n    \"Strobe Frequency\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"short\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"Strobe Density\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": 1,\n        \"parameterEnd\": 4,\n        \"comment\": \"Pixels\"\n      }\n    },\n    \"Strobe Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Strobe Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Strobe Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Strobe Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Strobe Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Hue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Saturation $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Intensity $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Look\",\n      \"channels\": [\n        \"Look Select\"\n      ]\n    },\n    {\n      \"name\": \"Master RGB\",\n      \"shortName\": \"x4RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB\",\n      \"shortName\": \"x2RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB\",\n      \"shortName\": \"x1RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB\",\n      \"shortName\": \"Od/EvRGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA\",\n      \"shortName\": \"x4RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA\",\n      \"shortName\": \"x2RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA\",\n      \"shortName\": \"x1RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA\",\n      \"shortName\": \"Od/EvRGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI\",\n      \"shortName\": \"x4HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI\",\n      \"shortName\": \"x2HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI\",\n      \"shortName\": \"x1HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI\",\n      \"shortName\": \"Od/EvHSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Strobe\",\n      \"shortName\": \"x4RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Strobe\",\n      \"shortName\": \"x2RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Strobe\",\n      \"shortName\": \"x1RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Strobe\",\n      \"shortName\": \"Od/EvRGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Strobe\",\n      \"shortName\": \"x4RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Strobe\",\n      \"shortName\": \"x2RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Strobe\",\n      \"shortName\": \"x1RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Strobe\",\n      \"shortName\": \"Od/EvRGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Strobe\",\n      \"shortName\": \"x4HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Strobe\",\n      \"shortName\": \"x2HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Strobe\",\n      \"shortName\": \"x1HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Strobe\",\n      \"shortName\": \"Od/EvHSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Random\",\n      \"shortName\": \"x4RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Random\",\n      \"shortName\": \"x2RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Random\",\n      \"shortName\": \"x1RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Random\",\n      \"shortName\": \"Od/EvRGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Random\",\n      \"shortName\": \"x4RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Random\",\n      \"shortName\": \"x2RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Random\",\n      \"shortName\": \"x1RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Random\",\n      \"shortName\": \"Od/EvRGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Random\",\n      \"shortName\": \"x4HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Random\",\n      \"shortName\": \"x2HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Random\",\n      \"shortName\": \"x1HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Random\",\n      \"shortName\": \"Od/EvHSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Random+OnTop\",\n      \"shortName\": \"x4RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Random+OnTop\",\n      \"shortName\": \"x2RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Random+OnTop\",\n      \"shortName\": \"x1RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Random+OnTop\",\n      \"shortName\": \"Od/EvRGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Random+OnTop\",\n      \"shortName\": \"x4RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Random+OnTop\",\n      \"shortName\": \"x2RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Random+OnTop\",\n      \"shortName\": \"x1RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Random+OnTop\",\n      \"shortName\": \"Od/EvRGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Random+OnTop\",\n      \"shortName\": \"x4HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Random+OnTop\",\n      \"shortName\": \"x2HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Random+OnTop\",\n      \"shortName\": \"x1HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Random+OnTop\",\n      \"shortName\": \"Od/EvHSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB OnTop\",\n      \"shortName\": \"x4RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB OnTop\",\n      \"shortName\": \"x2RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB OnTop\",\n      \"shortName\": \"x1RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB OnTop\",\n      \"shortName\": \"Od/EvRGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA OnTop\",\n      \"shortName\": \"x4RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA OnTop\",\n      \"shortName\": \"x2RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA OnTop\",\n      \"shortName\": \"x1RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA OnTop\",\n      \"shortName\": \"Od/EvRGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI OnTop\",\n      \"shortName\": \"x4HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI OnTop\",\n      \"shortName\": \"x2HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI OnTop\",\n      \"shortName\": \"x1HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI OnTop\",\n      \"shortName\": \"Od/EvHSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chroma-q/color-force-ii-48.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Color Force II 48\",\n  \"shortName\": \"CHCF248RGBA\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-13\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://chroma-q.com/assets/uploads/product_downloads/56078f55536c193d0748200af69d480f.pdf\"\n    ],\n    \"productPage\": [\n      \"https://chroma-q.com/products/color-force-ii-48\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=z5E7URWnnmQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1181, 191, 165],\n    \"weight\": 18,\n    \"power\": 400,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [22, 22]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [72.7, 81.2, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [16, 1, 1],\n    \"pixelGroups\": {\n      \"1/8\": [\"1\", \"2\"],\n      \"2/8\": [\"3\", \"4\"],\n      \"3/8\": [\"5\", \"6\"],\n      \"4/8\": [\"7\", \"8\"],\n      \"5/8\": [\"9\", \"10\"],\n      \"6/8\": [\"11\", \"12\"],\n      \"7/8\": [\"13\", \"14\"],\n      \"8/8\": [\"15\", \"16\"],\n      \"1/4\": { \"x\": [\"<=4\"] },\n      \"2/4\": { \"x\": [\">=5\", \"<=8\"] },\n      \"3/4\": { \"x\": [\">=9\", \"<=12\"] },\n      \"4/4\": { \"x\": [\">=13\"] },\n      \"1/2\": { \"x\": [\"<=8\"] },\n      \"2/2\": { \"x\": [\">=9\"] },\n      \"Master\": \"all\",\n      \"Odd\": { \"x\": [\"odd\"] },\n      \"Even\": { \"x\": [\"even\"] },\n      \"Every fourth\": { \"x\": [\"4n+1\"] },\n      \"Every fourth +1\": { \"x\": [\"4n+2\"] },\n      \"Every fourth +2\": { \"x\": [\"4n+3\"] },\n      \"Every fourth +3\": { \"x\": [\"4n\"] },\n      \"Every eighth\": { \"x\": [\"8n+1\"] },\n      \"Every eighth +1\": { \"x\": [\"8n+2\"] },\n      \"Every eighth +2\": { \"x\": [\"8n+3\"] },\n      \"Every eighth +3\": { \"x\": [\"8n+4\"] },\n      \"Every eighth +4\": { \"x\": [\"8n+5\"] },\n      \"Every eighth +5\": { \"x\": [\"8n+6\"] },\n      \"Every eighth +6\": { \"x\": [\"8n+7\"] },\n      \"Every eighth +7\": { \"x\": [\"8n\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Look Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Look 1 (default Red)\",\n          \"helpWanted\": \"Are the capability ranges correct?\"\n        },\n        {\n          \"dmxRange\": [9, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Look 2 (default Pink)\"\n        },\n        {\n          \"dmxRange\": [17, 25],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8800\"],\n          \"comment\": \"Look 3 (default Orange)\"\n        },\n        {\n          \"dmxRange\": [26, 33],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbb00\"],\n          \"comment\": \"Look 4 (default Light Orange)\"\n        },\n        {\n          \"dmxRange\": [34, 42],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Look 5 (default Yellow)\"\n        },\n        {\n          \"dmxRange\": [43, 51],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff88\"],\n          \"comment\": \"Look 6 (default Light Yellow)\"\n        },\n        {\n          \"dmxRange\": [52, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Look 7 (default Green)\"\n        },\n        {\n          \"dmxRange\": [60, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffaa\"],\n          \"comment\": \"Look 8 (default Light Green)\"\n        },\n        {\n          \"dmxRange\": [68, 75],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Look 9 (default Cyan)\"\n        },\n        {\n          \"dmxRange\": [76, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffff\"],\n          \"comment\": \"Look 10 (default Light Cyan)\"\n        },\n        {\n          \"dmxRange\": [85, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Look 11 (default Blue)\"\n        },\n        {\n          \"dmxRange\": [93, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#88aaff\"],\n          \"comment\": \"Look 12 (default Light Blue)\"\n        },\n        {\n          \"dmxRange\": [101, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaa5f\"],\n          \"comment\": \"Look 13 (default 2800K White)\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"comment\": \"Look 14 (default 3200K White)\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffcea6\"],\n          \"comment\": \"Look 15 (default 4000K White)\"\n        },\n        {\n          \"dmxRange\": [126, 133],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"comment\": \"Look 16 (default 5600K White)\"\n        },\n        {\n          \"dmxRange\": [134, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 17 (default empty)\"\n        },\n        {\n          \"dmxRange\": [142, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 18 (default empty)\"\n        },\n        {\n          \"dmxRange\": [150, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 19 (default empty)\"\n        },\n        {\n          \"dmxRange\": [158, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 20 (default empty)\"\n        },\n        {\n          \"dmxRange\": [166, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 21 (default empty)\"\n        },\n        {\n          \"dmxRange\": [175, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 22 (default empty)\"\n        },\n        {\n          \"dmxRange\": [183, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 23 (default empty)\"\n        },\n        {\n          \"dmxRange\": [191, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 24 (default empty)\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 25 (default empty)\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 26 (default empty)\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 27 (default empty)\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 28 (default empty)\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 29 (default empty)\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 30 (default empty)\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 31 (default empty)\"\n        }\n      ]\n    },\n    \"Strobe Frequency\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"short\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"Strobe Density\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": 1,\n        \"parameterEnd\": 16,\n        \"comment\": \"Pixels\"\n      }\n    },\n    \"Strobe Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Strobe Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Strobe Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Strobe Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Strobe Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Hue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Saturation $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Intensity $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Look\",\n      \"channels\": [\n        \"Look Select\"\n      ]\n    },\n    {\n      \"name\": \"Master RGB\",\n      \"shortName\": \"x16RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB\",\n      \"shortName\": \"x8RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB\",\n      \"shortName\": \"x4RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB\",\n      \"shortName\": \"x2RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB\",\n      \"shortName\": \"x1RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB\",\n      \"shortName\": \"Od/EvRGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB\",\n      \"shortName\": \"Skp3RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGB\",\n      \"shortName\": \"Skp6RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA\",\n      \"shortName\": \"x16RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA\",\n      \"shortName\": \"x8RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA\",\n      \"shortName\": \"x4RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA\",\n      \"shortName\": \"x2RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA\",\n      \"shortName\": \"x1RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA\",\n      \"shortName\": \"Od/EvRGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA\",\n      \"shortName\": \"Skp3RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGBA\",\n      \"shortName\": \"Skp6RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI\",\n      \"shortName\": \"x16HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI\",\n      \"shortName\": \"x8HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI\",\n      \"shortName\": \"x4HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI\",\n      \"shortName\": \"x2HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI\",\n      \"shortName\": \"x1HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI\",\n      \"shortName\": \"Od/EvHSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI\",\n      \"shortName\": \"Skp3HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth HSI\",\n      \"shortName\": \"Skp6HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Strobe\",\n      \"shortName\": \"x16RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Strobe\",\n      \"shortName\": \"x8RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB Strobe\",\n      \"shortName\": \"x4RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB Strobe\",\n      \"shortName\": \"x2RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Strobe\",\n      \"shortName\": \"x1RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Strobe\",\n      \"shortName\": \"Od/EvRGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB Strobe\",\n      \"shortName\": \"Skp3RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGB Strobe\",\n      \"shortName\": \"Skp6RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Strobe\",\n      \"shortName\": \"x16RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Strobe\",\n      \"shortName\": \"x8RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA Strobe\",\n      \"shortName\": \"x4RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA Strobe\",\n      \"shortName\": \"x2RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Strobe\",\n      \"shortName\": \"x1RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Strobe\",\n      \"shortName\": \"Od/EvRGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA Strobe\",\n      \"shortName\": \"Skp3RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGBA Strobe\",\n      \"shortName\": \"Skp6RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Strobe\",\n      \"shortName\": \"x16HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Strobe\",\n      \"shortName\": \"x8HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI Strobe\",\n      \"shortName\": \"x4HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI Strobe\",\n      \"shortName\": \"x2HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Strobe\",\n      \"shortName\": \"x1HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Strobe\",\n      \"shortName\": \"Od/EvHSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI Strobe\",\n      \"shortName\": \"Skp3HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth HSI Strobe\",\n      \"shortName\": \"Skp6HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Random\",\n      \"shortName\": \"x16RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Random\",\n      \"shortName\": \"x8RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB Random\",\n      \"shortName\": \"x4RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB Random\",\n      \"shortName\": \"x2RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Random\",\n      \"shortName\": \"x1RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Random\",\n      \"shortName\": \"Od/EvRGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB Random\",\n      \"shortName\": \"Skp3RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGB Random\",\n      \"shortName\": \"Skp6RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Random\",\n      \"shortName\": \"x16RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Random\",\n      \"shortName\": \"x8RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA Random\",\n      \"shortName\": \"x4RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA Random\",\n      \"shortName\": \"x2RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Random\",\n      \"shortName\": \"x1RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Random\",\n      \"shortName\": \"Od/EvRGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA Random\",\n      \"shortName\": \"Skp3RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGBA Random\",\n      \"shortName\": \"Skp6RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Random\",\n      \"shortName\": \"x16HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Random\",\n      \"shortName\": \"x8HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI Random\",\n      \"shortName\": \"x4HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI Random\",\n      \"shortName\": \"x2HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Random\",\n      \"shortName\": \"x1HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Random\",\n      \"shortName\": \"Od/EvHSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI Random\",\n      \"shortName\": \"Skp3HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth HSI Random\",\n      \"shortName\": \"Skp6HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Random+OnTop\",\n      \"shortName\": \"x16RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Random+OnTop\",\n      \"shortName\": \"x8RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB Random+OnTop\",\n      \"shortName\": \"x4RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB Random+OnTop\",\n      \"shortName\": \"x2RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Random+OnTop\",\n      \"shortName\": \"x1RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Random+OnTop\",\n      \"shortName\": \"Od/EvRGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB Random+OnTop\",\n      \"shortName\": \"Skp3RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGB Random+OnTop\",\n      \"shortName\": \"Skp6RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Random+OnTop\",\n      \"shortName\": \"x16RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Random+OnTop\",\n      \"shortName\": \"x8RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA Random+OnTop\",\n      \"shortName\": \"x4RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA Random+OnTop\",\n      \"shortName\": \"x2RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Random+OnTop\",\n      \"shortName\": \"x1RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Random+OnTop\",\n      \"shortName\": \"Od/EvRGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA Random+OnTop\",\n      \"shortName\": \"Skp3RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGBA Random+OnTop\",\n      \"shortName\": \"Skp6RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Random+OnTop\",\n      \"shortName\": \"x16HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Random+OnTop\",\n      \"shortName\": \"x8HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI Random+OnTop\",\n      \"shortName\": \"x4HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI Random+OnTop\",\n      \"shortName\": \"x2HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Random+OnTop\",\n      \"shortName\": \"x1HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Random+OnTop\",\n      \"shortName\": \"Od/EvHSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI Random+OnTop\",\n      \"shortName\": \"Skp3HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth HSI Random+OnTop\",\n      \"shortName\": \"Skp6HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB OnTop\",\n      \"shortName\": \"x16RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB OnTop\",\n      \"shortName\": \"x8RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB OnTop\",\n      \"shortName\": \"x4RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB OnTop\",\n      \"shortName\": \"x2RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB OnTop\",\n      \"shortName\": \"x1RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB OnTop\",\n      \"shortName\": \"Od/EvRGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB OnTop\",\n      \"shortName\": \"Skp3RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGB OnTop\",\n      \"shortName\": \"Skp6RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA OnTop\",\n      \"shortName\": \"x16RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA OnTop\",\n      \"shortName\": \"x8RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA OnTop\",\n      \"shortName\": \"x4RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA OnTop\",\n      \"shortName\": \"x2RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA OnTop\",\n      \"shortName\": \"x1RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA OnTop\",\n      \"shortName\": \"Od/EvRGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA OnTop\",\n      \"shortName\": \"Skp3RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth RGBA OnTop\",\n      \"shortName\": \"Skp6RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI OnTop\",\n      \"shortName\": \"x16HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI OnTop\",\n      \"shortName\": \"x8HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI OnTop\",\n      \"shortName\": \"x4HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI OnTop\",\n      \"shortName\": \"x2HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI OnTop\",\n      \"shortName\": \"x1HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI OnTop\",\n      \"shortName\": \"Od/EvHSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI OnTop\",\n      \"shortName\": \"Skp3HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every eighth HSI OnTop\",\n      \"shortName\": \"Skp6HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every eighth\", \"Every eighth +1\", \"Every eighth +2\", \"Every eighth +3\", \"Every eighth +4\", \"Every eighth +5\", \"Every eighth +6\", \"Every eighth +7\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/chroma-q/color-force-ii-72.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Color Force II 72\",\n  \"shortName\": \"CHCF272RGBA\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-13\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://chroma-q.com/assets/uploads/product_downloads/56078f55536c193d0748200af69d480f.pdf\"\n    ],\n    \"productPage\": [\n      \"https://chroma-q.com/products/color-force-ii-72\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=z5E7URWnnmQ\",\n      \"https://www.youtube.com/watch?v=YkycBKAxXGw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1759, 191, 165],\n    \"weight\": 24,\n    \"power\": 800,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [22, 22]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [72.7, 81.2, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [24, 1, 1],\n    \"pixelGroups\": {\n      \"1/12\": [\"1\", \"2\"],\n      \"2/12\": [\"3\", \"4\"],\n      \"3/12\": [\"5\", \"6\"],\n      \"4/12\": [\"7\", \"8\"],\n      \"5/12\": [\"9\", \"10\"],\n      \"6/12\": [\"11\", \"12\"],\n      \"7/12\": [\"13\", \"14\"],\n      \"8/12\": [\"15\", \"16\"],\n      \"9/12\": [\"17\", \"18\"],\n      \"10/12\": [\"19\", \"20\"],\n      \"11/12\": [\"21\", \"22\"],\n      \"12/12\": [\"23\", \"24\"],\n      \"1/8\": [\"1\", \"2\", \"3\"],\n      \"2/8\": [\"4\", \"5\", \"6\"],\n      \"3/8\": [\"7\", \"8\", \"9\"],\n      \"4/8\": [\"10\", \"11\", \"12\"],\n      \"5/8\": [\"13\", \"14\", \"15\"],\n      \"6/8\": [\"16\", \"17\", \"18\"],\n      \"7/8\": [\"19\", \"20\", \"21\"],\n      \"8/8\": [\"22\", \"23\", \"24\"],\n      \"1/6\": { \"x\": [\"<=4\"] },\n      \"2/6\": { \"x\": [\">=5\", \"<=8\"] },\n      \"3/6\": { \"x\": [\">=9\", \"<=12\"] },\n      \"4/6\": { \"x\": [\">=13\", \"<=16\"] },\n      \"5/6\": { \"x\": [\">=17\", \"<=20\"] },\n      \"6/6\": { \"x\": [\">=21\"] },\n      \"1/4\": { \"x\": [\"<=6\"] },\n      \"2/4\": { \"x\": [\">=7\", \"<=12\"] },\n      \"3/4\": { \"x\": [\">=13\", \"<=18\"] },\n      \"4/4\": { \"x\": [\">=19\"] },\n      \"1/3\": { \"x\": [\"<=8\"] },\n      \"2/3\": { \"x\": [\">=9\", \"<=16\"] },\n      \"3/3\": { \"x\": [\">=17\"] },\n      \"1/2\": { \"x\": [\"<=12\"] },\n      \"2/2\": { \"x\": [\">=13\"] },\n      \"Master\": \"all\",\n      \"Odd\": { \"x\": [\"odd\"] },\n      \"Even\": { \"x\": [\"even\"] },\n      \"Every third\": { \"x\": [\"3n+1\"] },\n      \"Every third +1\": { \"x\": [\"3n+2\"] },\n      \"Every third +2\": { \"x\": [\"3n\"] },\n      \"Every fourth\": { \"x\": [\"4n+1\"] },\n      \"Every fourth +1\": { \"x\": [\"4n+2\"] },\n      \"Every fourth +2\": { \"x\": [\"4n+3\"] },\n      \"Every fourth +3\": { \"x\": [\"4n\"] },\n      \"Every sixth\": { \"x\": [\"6n+1\"] },\n      \"Every sixth +1\": { \"x\": [\"6n+2\"] },\n      \"Every sixth +2\": { \"x\": [\"6n+3\"] },\n      \"Every sixth +3\": { \"x\": [\"6n+4\"] },\n      \"Every sixth +4\": { \"x\": [\"6n+5\"] },\n      \"Every sixth +5\": { \"x\": [\"6n\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Look Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Look 1 (default Red)\",\n          \"helpWanted\": \"Are the capability ranges correct?\"\n        },\n        {\n          \"dmxRange\": [9, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Look 2 (default Pink)\"\n        },\n        {\n          \"dmxRange\": [17, 25],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8800\"],\n          \"comment\": \"Look 3 (default Orange)\"\n        },\n        {\n          \"dmxRange\": [26, 33],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbb00\"],\n          \"comment\": \"Look 4 (default Light Orange)\"\n        },\n        {\n          \"dmxRange\": [34, 42],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Look 5 (default Yellow)\"\n        },\n        {\n          \"dmxRange\": [43, 51],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff88\"],\n          \"comment\": \"Look 6 (default Light Yellow)\"\n        },\n        {\n          \"dmxRange\": [52, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Look 7 (default Green)\"\n        },\n        {\n          \"dmxRange\": [60, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffaa\"],\n          \"comment\": \"Look 8 (default Light Green)\"\n        },\n        {\n          \"dmxRange\": [68, 75],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Look 9 (default Cyan)\"\n        },\n        {\n          \"dmxRange\": [76, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffff\"],\n          \"comment\": \"Look 10 (default Light Cyan)\"\n        },\n        {\n          \"dmxRange\": [85, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Look 11 (default Blue)\"\n        },\n        {\n          \"dmxRange\": [93, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#88aaff\"],\n          \"comment\": \"Look 12 (default Light Blue)\"\n        },\n        {\n          \"dmxRange\": [101, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaa5f\"],\n          \"comment\": \"Look 13 (default 2800K White)\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"comment\": \"Look 14 (default 3200K White)\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffcea6\"],\n          \"comment\": \"Look 15 (default 4000K White)\"\n        },\n        {\n          \"dmxRange\": [126, 133],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"comment\": \"Look 16 (default 5600K White)\"\n        },\n        {\n          \"dmxRange\": [134, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 17 (default empty)\"\n        },\n        {\n          \"dmxRange\": [142, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 18 (default empty)\"\n        },\n        {\n          \"dmxRange\": [150, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 19 (default empty)\"\n        },\n        {\n          \"dmxRange\": [158, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 20 (default empty)\"\n        },\n        {\n          \"dmxRange\": [166, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 21 (default empty)\"\n        },\n        {\n          \"dmxRange\": [175, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 22 (default empty)\"\n        },\n        {\n          \"dmxRange\": [183, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 23 (default empty)\"\n        },\n        {\n          \"dmxRange\": [191, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 24 (default empty)\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 25 (default empty)\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 26 (default empty)\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 27 (default empty)\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 28 (default empty)\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 29 (default empty)\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 30 (default empty)\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Look 31 (default empty)\"\n        }\n      ]\n    },\n    \"Strobe Frequency\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"short\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"Strobe Density\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": 1,\n        \"parameterEnd\": 24,\n        \"comment\": \"Pixels\"\n      }\n    },\n    \"Strobe Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Strobe Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Strobe Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Strobe Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Strobe Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Hue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Saturation $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Intensity $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Look\",\n      \"channels\": [\n        \"Look Select\"\n      ]\n    },\n    {\n      \"name\": \"Master RGB\",\n      \"shortName\": \"x24RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB\",\n      \"shortName\": \"x12RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGB\",\n      \"shortName\": \"x8RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB\",\n      \"shortName\": \"x6RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGB\",\n      \"shortName\": \"x4RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB\",\n      \"shortName\": \"x3RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGB\",\n      \"shortName\": \"x2RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB\",\n      \"shortName\": \"x1RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB\",\n      \"shortName\": \"Od/EvRGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGB\",\n      \"shortName\": \"Skp2RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB\",\n      \"shortName\": \"Skp3RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGB\",\n      \"shortName\": \"Skp6RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA\",\n      \"shortName\": \"x24RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA\",\n      \"shortName\": \"x12RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGBA\",\n      \"shortName\": \"x8RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA\",\n      \"shortName\": \"x6RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGBA\",\n      \"shortName\": \"x4RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA\",\n      \"shortName\": \"x3RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGBA\",\n      \"shortName\": \"x2RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA\",\n      \"shortName\": \"x1RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA\",\n      \"shortName\": \"Od/EvRGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGBA\",\n      \"shortName\": \"Skp2RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA\",\n      \"shortName\": \"Skp3RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGBA\",\n      \"shortName\": \"Skp6RGBA\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI\",\n      \"shortName\": \"x24HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI\",\n      \"shortName\": \"x12HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds HSI\",\n      \"shortName\": \"x8HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI\",\n      \"shortName\": \"x6HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths HSI\",\n      \"shortName\": \"x4HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI\",\n      \"shortName\": \"x3HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths HSI\",\n      \"shortName\": \"x2HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI\",\n      \"shortName\": \"x1HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI\",\n      \"shortName\": \"Od/EvHSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third HSI\",\n      \"shortName\": \"Skp2HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI\",\n      \"shortName\": \"Skp3HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth HSI\",\n      \"shortName\": \"Skp6HSI\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Strobe\",\n      \"shortName\": \"x24RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Strobe\",\n      \"shortName\": \"x12RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGB Strobe\",\n      \"shortName\": \"x8RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB Strobe\",\n      \"shortName\": \"x6RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGB Strobe\",\n      \"shortName\": \"x4RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB Strobe\",\n      \"shortName\": \"x3RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGB Strobe\",\n      \"shortName\": \"x2RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Strobe\",\n      \"shortName\": \"x1RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Strobe\",\n      \"shortName\": \"Od/EvRGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGB Strobe\",\n      \"shortName\": \"Skp2RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB Strobe\",\n      \"shortName\": \"Skp3RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGB Strobe\",\n      \"shortName\": \"Skp6RGBStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Strobe\",\n      \"shortName\": \"x24RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Strobe\",\n      \"shortName\": \"x12RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGBA Strobe\",\n      \"shortName\": \"x8RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA Strobe\",\n      \"shortName\": \"x6RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGBA Strobe\",\n      \"shortName\": \"x4RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA Strobe\",\n      \"shortName\": \"x3RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGBA Strobe\",\n      \"shortName\": \"x2RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Strobe\",\n      \"shortName\": \"x1RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Strobe\",\n      \"shortName\": \"Od/EvRGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGBA Strobe\",\n      \"shortName\": \"Skp2RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA Strobe\",\n      \"shortName\": \"Skp3RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGBA Strobe\",\n      \"shortName\": \"Skp6RGBAStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Strobe\",\n      \"shortName\": \"x24HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Strobe\",\n      \"shortName\": \"x12HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds HSI Strobe\",\n      \"shortName\": \"x8HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI Strobe\",\n      \"shortName\": \"x6HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths HSI Strobe\",\n      \"shortName\": \"x4HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI Strobe\",\n      \"shortName\": \"x3HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths HSI Strobe\",\n      \"shortName\": \"x2HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Strobe\",\n      \"shortName\": \"x1HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Strobe\",\n      \"shortName\": \"Od/EvHSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third HSI Strobe\",\n      \"shortName\": \"Skp2HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI Strobe\",\n      \"shortName\": \"Skp3HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth HSI Strobe\",\n      \"shortName\": \"Skp6HSIStrb\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Random\",\n      \"shortName\": \"x24RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Random\",\n      \"shortName\": \"x12RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGB Random\",\n      \"shortName\": \"x8RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB Random\",\n      \"shortName\": \"x6RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGB Random\",\n      \"shortName\": \"x4RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB Random\",\n      \"shortName\": \"x3RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGB Random\",\n      \"shortName\": \"x2RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Random\",\n      \"shortName\": \"x1RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Random\",\n      \"shortName\": \"Od/EvRGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGB Random\",\n      \"shortName\": \"Skp2RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB Random\",\n      \"shortName\": \"Skp3RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGB Random\",\n      \"shortName\": \"Skp6RGBRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Random\",\n      \"shortName\": \"x24RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Random\",\n      \"shortName\": \"x12RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGBA Random\",\n      \"shortName\": \"x8RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA Random\",\n      \"shortName\": \"x6RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGBA Random\",\n      \"shortName\": \"x4RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA Random\",\n      \"shortName\": \"x3RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGBA Random\",\n      \"shortName\": \"x2RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Random\",\n      \"shortName\": \"x1RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Random\",\n      \"shortName\": \"Od/EvRGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGBA Random\",\n      \"shortName\": \"Skp2RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA Random\",\n      \"shortName\": \"Skp3RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGBA Random\",\n      \"shortName\": \"Skp6RGBARandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Random\",\n      \"shortName\": \"x24HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Random\",\n      \"shortName\": \"x12HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds HSI Random\",\n      \"shortName\": \"x8HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI Random\",\n      \"shortName\": \"x6HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths HSI Random\",\n      \"shortName\": \"x4HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI Random\",\n      \"shortName\": \"x3HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths HSI Random\",\n      \"shortName\": \"x2HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Random\",\n      \"shortName\": \"x1HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Random\",\n      \"shortName\": \"Od/EvHSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third HSI Random\",\n      \"shortName\": \"Skp2HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI Random\",\n      \"shortName\": \"Skp3HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth HSI Random\",\n      \"shortName\": \"Skp6HSIRandom\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB Random+OnTop\",\n      \"shortName\": \"x24RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB Random+OnTop\",\n      \"shortName\": \"x12RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGB Random+OnTop\",\n      \"shortName\": \"x8RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB Random+OnTop\",\n      \"shortName\": \"x6RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGB Random+OnTop\",\n      \"shortName\": \"x4RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB Random+OnTop\",\n      \"shortName\": \"x3RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGB Random+OnTop\",\n      \"shortName\": \"x2RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB Random+OnTop\",\n      \"shortName\": \"x1RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB Random+OnTop\",\n      \"shortName\": \"Od/EvRGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGB Random+OnTop\",\n      \"shortName\": \"Skp2RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB Random+OnTop\",\n      \"shortName\": \"Skp3RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGB Random+OnTop\",\n      \"shortName\": \"Skp6RGBRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA Random+OnTop\",\n      \"shortName\": \"x24RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA Random+OnTop\",\n      \"shortName\": \"x12RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGBA Random+OnTop\",\n      \"shortName\": \"x8RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA Random+OnTop\",\n      \"shortName\": \"x6RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGBA Random+OnTop\",\n      \"shortName\": \"x4RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA Random+OnTop\",\n      \"shortName\": \"x3RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGBA Random+OnTop\",\n      \"shortName\": \"x2RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA Random+OnTop\",\n      \"shortName\": \"x1RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA Random+OnTop\",\n      \"shortName\": \"Od/EvRGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGBA Random+OnTop\",\n      \"shortName\": \"Skp2RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA Random+OnTop\",\n      \"shortName\": \"Skp3RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGBA Random+OnTop\",\n      \"shortName\": \"Skp6RGBARandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI Random+OnTop\",\n      \"shortName\": \"x24HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI Random+OnTop\",\n      \"shortName\": \"x12HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds HSI Random+OnTop\",\n      \"shortName\": \"x8HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI Random+OnTop\",\n      \"shortName\": \"x6HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths HSI Random+OnTop\",\n      \"shortName\": \"x4HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI Random+OnTop\",\n      \"shortName\": \"x3HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths HSI Random+OnTop\",\n      \"shortName\": \"x2HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI Random+OnTop\",\n      \"shortName\": \"x1HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI Random+OnTop\",\n      \"shortName\": \"Od/EvHSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third HSI Random+OnTop\",\n      \"shortName\": \"Skp2HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI Random+OnTop\",\n      \"shortName\": \"Skp3HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth HSI Random+OnTop\",\n      \"shortName\": \"Skp6HSIRandomOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Density\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGB OnTop\",\n      \"shortName\": \"x24RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGB OnTop\",\n      \"shortName\": \"x12RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGB OnTop\",\n      \"shortName\": \"x8RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGB OnTop\",\n      \"shortName\": \"x6RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGB OnTop\",\n      \"shortName\": \"x4RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGB OnTop\",\n      \"shortName\": \"x3RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGB OnTop\",\n      \"shortName\": \"x2RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGB OnTop\",\n      \"shortName\": \"x1RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGB OnTop\",\n      \"shortName\": \"Od/EvRGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGB OnTop\",\n      \"shortName\": \"Skp2RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGB OnTop\",\n      \"shortName\": \"Skp3RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGB OnTop\",\n      \"shortName\": \"Skp6RGBOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master RGBA OnTop\",\n      \"shortName\": \"x24RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves RGBA OnTop\",\n      \"shortName\": \"x12RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds RGBA OnTop\",\n      \"shortName\": \"x8RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths RGBA OnTop\",\n      \"shortName\": \"x6RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths RGBA OnTop\",\n      \"shortName\": \"x4RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths RGBA OnTop\",\n      \"shortName\": \"x3RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths RGBA OnTop\",\n      \"shortName\": \"x2RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual RGBA OnTop\",\n      \"shortName\": \"x1RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even RGBA OnTop\",\n      \"shortName\": \"Od/EvRGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third RGBA OnTop\",\n      \"shortName\": \"Skp2RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth RGBA OnTop\",\n      \"shortName\": \"Skp3RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth RGBA OnTop\",\n      \"shortName\": \"Skp6RGBAOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Red\",\n        \"Strobe Green\",\n        \"Strobe Blue\",\n        \"Strobe Amber\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Master HSI OnTop\",\n      \"shortName\": \"x24HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Halves HSI OnTop\",\n      \"shortName\": \"x12HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Thirds HSI OnTop\",\n      \"shortName\": \"x8HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Fourths HSI OnTop\",\n      \"shortName\": \"x6HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Sixths HSI OnTop\",\n      \"shortName\": \"x4HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Eighths HSI OnTop\",\n      \"shortName\": \"x3HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/8\", \"2/8\", \"3/8\", \"4/8\", \"5/8\", \"6/8\", \"7/8\", \"8/8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Twelths HSI OnTop\",\n      \"shortName\": \"x2HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/12\", \"2/12\", \"3/12\", \"4/12\", \"5/12\", \"6/12\", \"7/12\", \"8/12\", \"9/12\", \"10/12\", \"11/12\", \"12/12\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Individual HSI OnTop\",\n      \"shortName\": \"x1HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Odd/Even HSI OnTop\",\n      \"shortName\": \"Od/EvHSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Odd\", \"Even\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every third HSI OnTop\",\n      \"shortName\": \"Skp2HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every third\", \"Every third +1\", \"Every third +2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every fourth HSI OnTop\",\n      \"shortName\": \"Skp3HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every fourth\", \"Every fourth +1\", \"Every fourth +2\", \"Every fourth +3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Every sixth HSI OnTop\",\n      \"shortName\": \"Skp6HSIOnTop\",\n      \"channels\": [\n        \"Strobe Frequency\",\n        \"Strobe Duration\",\n        \"Strobe Hue\",\n        \"Strobe Saturation\",\n        \"Strobe Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Every sixth\", \"Every sixth +1\", \"Every sixth +2\", \"Every sixth +3\", \"Every sixth +4\", \"Every sixth +5\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/cinetec/par-18x15w-rgbwa.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PAR 18x15W RGBWA\",\n  \"shortName\": \"SFLP17A\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Arthur\"],\n    \"createDate\": \"2019-02-18\",\n    \"lastModifyDate\": \"2019-02-18\"\n  },\n  \"helpWanted\": \"Please provide a manual if possible. Why are there two color macro channels? Is the 5-channel mode correct?\",\n  \"links\": {\n    \"other\": [\n      \"https://www.9pboutik.com/boutique/lumieres/par-led/par-18x15-rgbwa-pro.html\"\n    ]\n  },\n  \"physical\": {\n    \"weight\": 6.6,\n    \"power\": 270,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18x15W RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 10,\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"comment\": \"Color Mix\",\n        \"helpWanted\": \"At which DMX values can which color be selected?\"\n      }\n    },\n    \"Color Macros 2\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"comment\": \"Color Mix 2\",\n        \"helpWanted\": \"At which DMX values can which color be selected?\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Macros 2\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/clay-paky/a-leda-b-eye-k10.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"A.leda B-EYE K10\",\n  \"shortName\": \"A.leda B-EYE K10\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-09-10\",\n    \"lastModifyDate\": \"2019-09-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://e-assist.tech/servlet/checkDocumentsFile?Id=729\"\n    ],\n    \"productPage\": [\n      \"https://www.claypaky.it/products/a-leda-b-eye-k10/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=8pmvT2FVHec\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [358, 494, 253],\n    \"weight\": 15,\n    \"power\": 450,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Osram Ostar 15W RGBW LED\",\n      \"lumens\": 9800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 60]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null, null, \"13\", null, \"14\", null, null, null],\n        [null, \"12\", null, null, null, null, null, \"15\", null],\n        [null, null, null,  \"4\", null,  \"5\", null, null, null],\n        [\"11\", null, null, null, null, null, null, null, \"16\"],\n        [null, null,  \"3\", null,  \"1\", null,  \"6\", null, null],\n        [\"10\", null, null, null, null, null, null, null, \"17\"],\n        [null, null, null,  \"2\", null,  \"7\", null, null, null],\n        [null,  \"9\", null, null, null, null, null, \"18\", null],\n        [null, null, null,  \"8\", null, \"19\", null, null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Shape\": \"all\",\n      \"Foreground\": \"all\",\n      \"Background\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Linear CTO\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"8000K\",\n          \"colorTemperatureEnd\": \"2500K\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#f4ffa4\"],\n          \"colorTemperature\": \"7000K\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffe48c\"],\n          \"colorTemperature\": \"3700K\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffbc6e\"],\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Black\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [20, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 10 Medium Yellow\",\n          \"colors\": [\"#9c7e00\"]\n        },\n        {\n          \"dmxRange\": [23, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 13 Straw Tint\",\n          \"colors\": [\"#987309\"]\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 17 Surprise Peach\",\n          \"colors\": [\"#c67209\"]\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 19 Fire\",\n          \"colors\": [\"#ff3800\"]\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 20 Medium Amber\",\n          \"colors\": [\"#ff8700\"]\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 21 Gold Amber\",\n          \"colors\": [\"#ff6400\"]\n        },\n        {\n          \"dmxRange\": [32, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 22 Dark Amber\",\n          \"colors\": [\"#ff4100\"]\n        },\n        {\n          \"dmxRange\": [35, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 25 Sunrise Red\",\n          \"colors\": [\"#ff5302\"]\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 35 Light Pink\",\n          \"colors\": [\"#ffa35b\"]\n        },\n        {\n          \"dmxRange\": [46, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 36 Medium Pink\",\n          \"colors\": [\"#ff894b\"]\n        },\n        {\n          \"dmxRange\": [49, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 39 Pink Carnation\",\n          \"colors\": [\"#ff9d56\"]\n        },\n        {\n          \"dmxRange\": [62, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 52 Light Lavender\",\n          \"colors\": [\"#ffb689\"]\n        },\n        {\n          \"dmxRange\": [68, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 58 Lavender\",\n          \"colors\": [\"#ffb6c0\"]\n        },\n        {\n          \"dmxRange\": [78, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 68 Sky Blue\",\n          \"colors\": [\"#00ff87\"]\n        },\n        {\n          \"dmxRange\": [89, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 79 Just Blue\",\n          \"colors\": [\"#00c282\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 90 Dark Yellow Green\",\n          \"colors\": [\"#29db00\"]\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 100 Spring Yellow\",\n          \"colors\": [\"#f5ca00\"]\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 102 Light Amber\",\n          \"colors\": [\"#eda300\"]\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 103 Straw\",\n          \"colors\": [\"#ffc33b\"]\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 104 Deep Amber\",\n          \"colors\": [\"#ffa600\"]\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 105 Orange\",\n          \"colors\": [\"#ff7a00\"]\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 107 Light Rose\",\n          \"colors\": [\"#ff8d1f\"]\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 108 English Rose\",\n          \"colors\": [\"#ff9417\"]\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 109 Light Salmon\",\n          \"colors\": [\"#ff8a1f\"]\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 110 Middle Rose\",\n          \"colors\": [\"#d9821c\"]\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 111 Dark Pink\",\n          \"colors\": [\"#ff6d21\"]\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 113 Magenta\",\n          \"colors\": [\"#ff140f\"]\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 115 Peacock Blue\",\n          \"colors\": [\"#33ff33\"]\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 116 Med Blue Green\",\n          \"colors\": [\"#ceff38\"]\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 117 Steel Blue\",\n          \"colors\": [\"#ceff38\"]\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 118 Light Blue\",\n          \"colors\": [\"#4aff52\"]\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 119 Dark Blue\",\n          \"colors\": [\"#00baff\"]\n        },\n        {\n          \"dmxRange\": [131, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 121 Leaf Green\",\n          \"colors\": [\"#ceff00\"]\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 124 Dark Green\",\n          \"colors\": [\"#54ff0d\"]\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 126 Mauve\",\n          \"colors\": [\"#e32938\"]\n        },\n        {\n          \"dmxRange\": [138, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\",\n          \"colors\": [\"#ff3524\"]\n        },\n        {\n          \"dmxRange\": [142, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 132 Medium Blue\",\n          \"colors\": [\"#00ff8f\"]\n        },\n        {\n          \"dmxRange\": [145, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 135 Deep Golden Amber\",\n          \"colors\": [\"#ff3a00\"]\n        },\n        {\n          \"dmxRange\": [146, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 136 Pale Lavender\",\n          \"colors\": [\"#ffc53d\"]\n        },\n        {\n          \"dmxRange\": [147, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 137 Special Lavender\",\n          \"colors\": [\"#dbc54f\"]\n        },\n        {\n          \"dmxRange\": [149, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 139 Primary Green\",\n          \"colors\": [\"#4dff00\"]\n        },\n        {\n          \"dmxRange\": [151, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 141 Bright Blue\",\n          \"colors\": [\"#00ff57\"]\n        },\n        {\n          \"dmxRange\": [157, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 147 Apricot\",\n          \"colors\": [\"#ff8f0d\"]\n        },\n        {\n          \"dmxRange\": [162, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 152 Pale Gold\",\n          \"colors\": [\"#fdab1a\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 158 Deep Orange\",\n          \"colors\": [\"#de5400\"]\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 162 Bastard Amber\",\n          \"colors\": [\"#ffb51c\"]\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 164 Flame Red\",\n          \"colors\": [\"#ff2e02\"]\n        },\n        {\n          \"dmxRange\": [175, 178],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 165 Daylight Blue\",\n          \"colors\": [\"#52d65a\"]\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 169 Lilac Tint\",\n          \"colors\": [\"#ffc731\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 170 Deep Lavender\",\n          \"colors\": [\"#ffa840\"]\n        },\n        {\n          \"dmxRange\": [184, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 174 Dark Steel Blue\",\n          \"colors\": [\"#ffe756\"]\n        },\n        {\n          \"dmxRange\": [191, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 181 Congo Blue\",\n          \"colors\": [\"#4d00ff\"]\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 197 Alice Blue\",\n          \"colors\": [\"#80ff8f\"]\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dirty White\",\n          \"colors\": [\"#ffffbd\"]\n        },\n        {\n          \"dmxRange\": [209, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#fff5a1\"]\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"210deg\"\n      }\n    },\n    \"Maintenance\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan Tilt Fast (Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [25, 37],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan Tilt Normal\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [38, 42],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 1\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [43, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 2\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [48, 52],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 3 (Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [53, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 4\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [58, 62],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW Gamma curve 1 – gamma = 1.0\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [63, 67],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW Gamma curve 2 – gamma = 1.5 (Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [68, 72],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW Gamma curve 3 – gamma = 2.0\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [73, 77],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation OFF (Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [78, 82],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 750 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [83, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 1000 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [88, 92],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 1200 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [93, 97],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 2000 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [98, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 2500 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [103, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pixel map enabled\"\n        },\n        {\n          \"dmxRange\": [106, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 76],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom reset\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [77, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt reset\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Complete reset\",\n          \"hold\": \"5s\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"Zoom\",\n          \"angleStart\": \"4deg\",\n          \"angleEnd\": \"59.8deg\",\n          \"switchChannels\": {\n            \"Lens Rotation / Rotation Offset\": \"Lens Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Zoom\",\n          \"angle\": \"60deg\",\n          \"switchChannels\": {\n            \"Lens Rotation / Rotation Offset\": \"Lens Rotation Offset\"\n          }\n        }\n      ]\n    },\n    \"Lens Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"60deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"10rpm\",\n          \"speedEnd\": \"3rpm\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"-3rpm\",\n          \"speedEnd\": \"-10rpm\"\n        }\n      ]\n    },\n    \"Lens Rotation Offset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"4deg\",\n          \"comment\": \"Offset\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Rotation\",\n          \"angle\": \"0deg\",\n          \"comment\": \"Offset\"\n        }\n      ]\n    },\n    \"Shape Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single ring (ramp –/+)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Size Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Flash Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Filled rings (ramp –/+)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Size Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Flash Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open/Close 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Size Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Flash Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open/Close 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Size Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Flash Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random pixels 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Speed With Fade\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random pixels 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Speed With Fade\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Pixel Density\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow 1 (variable speed)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow 2 (variable color offset)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Color Offset\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fan\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bar 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Half moon\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Effect\",\n          \"effectName\": \"Triangle\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Segment 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"Arc 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Arc 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bar 2 (variable size)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random explosion\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Segment 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping section\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ramp by 6\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ramp by 4\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Left/right scrolling bar\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Up/down scrolling bar\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bar 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical arc 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Horizontal arc 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mirrored pixel\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 4\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 5\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Semi arc (ramp –/+)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping arc section\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 6\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical ramp by 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Following pixel by 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"Syncopation\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [57, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [59, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical pixel scrolling\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random vertical section\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random central section\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random ring 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random ring 1+3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 66],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random ring 2+3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [67, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single pixel ring 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Number of Rotating\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single pixel ring 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Number of Rotating\"\n          }\n        },\n        {\n          \"dmxRange\": [69, 69],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        }\n      ]\n    },\n    \"Shape Size Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\",\n          \"comment\": \"Radius size\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\",\n          \"comment\": \"Closing\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Opening\"\n        }\n      ]\n    },\n    \"Shape Speed With Fade\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"fade out\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"fade in/out\"\n        }\n      ]\n    },\n    \"Shape Rotation Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Shape Color Offset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Shape Flash Distribution\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\",\n          \"comment\": \"Continuous flash distribution\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random flash distribution\"\n        }\n      ]\n    },\n    \"Shape Random Distribution\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": 2,\n        \"parameterEnd\": 20,\n        \"comment\": \"Pixels\"\n      }\n    },\n    \"Shape Pixel Density\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"helpWanted\": \"Is this the same as \\\"Shape Random Distribution\\\"?\"\n      }\n    },\n    \"Shape Angle Offset\": {\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Shape Width\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"Shape Macro Offset\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"Shape Number of Rotating\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\",\n        \"helpWanted\": \"What number is this? The number of rotating rings maybe?\"\n      }\n    },\n    \"Shape Fade Gamma\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Snap\"\n        },\n        {\n          \"dmxRange\": [16, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Smooth, fading curve gamma\",\n          \"parameterStart\": 0.5,\n          \"parameterEnd\": 2\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Smooth, fading curve with automatic gamma\"\n        }\n      ]\n    },\n    \"Shape Linear Fade\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\",\n        \"helpWanted\": \"Is this really a time unit? What is the difference to Shape Transition then?\"\n      }\n    },\n    \"Shape Linear Fade and Wake Length\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\",\n        \"helpWanted\": \"Is this really a time unit? What is the difference to Shape Transition then?\"\n      }\n    },\n    \"Shape Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Shape Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Shape Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Shape White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shape Transition\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Time\",\n          \"time\": \"instant\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Time\",\n          \"timeStart\": \"100ms\",\n          \"timeEnd\": \"4000ms\"\n        }\n      ]\n    },\n    \"Background Select\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No selection (wash)\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 2\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 3\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 3\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 2\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 2 + Ring 3\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 2 + Ring 3\"\n        },\n        {\n          \"dmxRange\": [16, 254],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No selection (wash)\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mirror effect\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red\": {\n      \"fineChannelAliases\": [\"$pixelKey Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"fineChannelAliases\": [\"$pixelKey Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"fineChannelAliases\": [\"$pixelKey Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"fineChannelAliases\": [\"$pixelKey White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Dimmer\": {\n      \"fineChannelAliases\": [\"$pixelKey Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"$pixelKey Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red LED $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green LED $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue LED $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White LED $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"channels\": [\n        \"Master Red\",\n        \"Master Red fine\",\n        \"Master Green\",\n        \"Master Green fine\",\n        \"Master Blue\",\n        \"Master Blue fine\",\n        \"Master White\",\n        \"Master White fine\",\n        \"Linear CTO\",\n        \"Color Presets\",\n        \"Master Strobe\",\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Maintenance\",\n        \"Reset\",\n        \"Zoom\",\n        \"Lens Rotation / Rotation Offset\"\n      ]\n    },\n    {\n      \"name\": \"Shapes\",\n      \"channels\": [\n        \"Master Red\",\n        \"Master Red fine\",\n        \"Master Green\",\n        \"Master Green fine\",\n        \"Master Blue\",\n        \"Master Blue fine\",\n        \"Master White\",\n        \"Master White fine\",\n        \"Linear CTO\",\n        \"Color Presets\",\n        \"Master Strobe\",\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Maintenance\",\n        \"Reset\",\n        \"Zoom\",\n        \"Lens Rotation / Rotation Offset\",\n        \"Shape Selection\",\n        \"Shape Speed\",\n        \"Shape Fade\",\n        \"Shape Red\",\n        \"Shape Green\",\n        \"Shape Blue\",\n        \"Shape White\",\n        \"Shape Dimmer\",\n        \"Background Dimmer\",\n        \"Shape Transition\",\n        \"Shape Offset\",\n        \"Foreground Strobe\",\n        \"Background Strobe\",\n        \"Background Select\"\n      ]\n    },\n    {\n      \"name\": \"Pixel RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red LED $pixelKey\",\n            \"Green LED $pixelKey\",\n            \"Blue LED $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Pixel RGBW\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red LED $pixelKey\",\n            \"Green LED $pixelKey\",\n            \"Blue LED $pixelKey\",\n            \"White LED $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/clay-paky/a-leda-b-eye-k20.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"A.leda B-EYE K20\",\n  \"shortName\": \"A.leda B-EYE K20\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Sebastian Portilla\", \"Felix Edelmann\"],\n    \"createDate\": \"2019-09-10\",\n    \"lastModifyDate\": \"2019-09-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://e-assist.tech/servlet/checkDocumentsFile?Id=729\"\n    ],\n    \"productPage\": [\n      \"https://www.claypaky.it/products/a-leda-b-eye-k20/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=8pmvT2FVHec\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [395, 476, 330],\n    \"weight\": 21,\n    \"power\": 555,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Osram Ostar 15W RGBW LED\",\n      \"lumens\": 9800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 60]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null, null, null, null, null, \"28\", null, \"29\", null, null, null, null, null, null],\n        [null, null, null, null, \"27\", null, null, null, null, null, \"30\", null, null, null, null],\n        [null, null, \"26\", null, null, null, \"13\", null, \"14\", null, null, null, \"31\", null, null],\n        [null, null, null, null, \"12\", null, null, null, null, null, \"15\", null, null, null, null],\n        [null, \"25\", null, null, null, null,  \"4\", null,  \"5\", null, null, null, null, \"32\", null],\n        [null, null, null, \"11\", null, null, null, null, null, null, null, \"16\", null, null, null],\n        [\"24\", null, null, null, null,  \"3\", null,  \"1\", null,  \"6\", null, null, null, null, \"33\"],\n        [null, null, null, \"10\", null, null, null, null, null, null, null, \"17\", null, null, null],\n        [null, \"23\", null, null, null, null,  \"2\", null,  \"7\", null, null, null, null, \"34\", null],\n        [null, null, null, null,  \"9\", null, null, null, null, null, \"18\", null, null, null, null],\n        [null, null, \"22\", null, null, null,  \"8\", null, \"19\", null, null, null, \"35\", null, null],\n        [null, null, null, null, \"21\", null, null, null, null, null, \"36\", null, null, null, null],\n        [null, null, null, null, null, null, \"20\", null, \"37\", null, null, null, null, null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Shape\": \"all\",\n      \"Foreground\": \"all\",\n      \"Background\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Linear CTO\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"8000K\",\n          \"colorTemperatureEnd\": \"2500K\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#f4ffa4\"],\n          \"colorTemperature\": \"7000K\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffe48c\"],\n          \"colorTemperature\": \"3700K\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffbc6e\"],\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Black\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [20, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 10 Medium Yellow\",\n          \"colors\": [\"#9c7e00\"]\n        },\n        {\n          \"dmxRange\": [23, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 13 Straw Tint\",\n          \"colors\": [\"#987309\"]\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 17 Surprise Peach\",\n          \"colors\": [\"#c67209\"]\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 19 Fire\",\n          \"colors\": [\"#ff3800\"]\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 20 Medium Amber\",\n          \"colors\": [\"#ff8700\"]\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 21 Gold Amber\",\n          \"colors\": [\"#ff6400\"]\n        },\n        {\n          \"dmxRange\": [32, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 22 Dark Amber\",\n          \"colors\": [\"#ff4100\"]\n        },\n        {\n          \"dmxRange\": [35, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 25 Sunrise Red\",\n          \"colors\": [\"#ff5302\"]\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 35 Light Pink\",\n          \"colors\": [\"#ffa35b\"]\n        },\n        {\n          \"dmxRange\": [46, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 36 Medium Pink\",\n          \"colors\": [\"#ff894b\"]\n        },\n        {\n          \"dmxRange\": [49, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 39 Pink Carnation\",\n          \"colors\": [\"#ff9d56\"]\n        },\n        {\n          \"dmxRange\": [62, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 52 Light Lavender\",\n          \"colors\": [\"#ffb689\"]\n        },\n        {\n          \"dmxRange\": [68, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 58 Lavender\",\n          \"colors\": [\"#ffb6c0\"]\n        },\n        {\n          \"dmxRange\": [78, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 68 Sky Blue\",\n          \"colors\": [\"#00ff87\"]\n        },\n        {\n          \"dmxRange\": [89, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 79 Just Blue\",\n          \"colors\": [\"#00c282\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 90 Dark Yellow Green\",\n          \"colors\": [\"#29db00\"]\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 100 Spring Yellow\",\n          \"colors\": [\"#f5ca00\"]\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 102 Light Amber\",\n          \"colors\": [\"#eda300\"]\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 103 Straw\",\n          \"colors\": [\"#ffc33b\"]\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 104 Deep Amber\",\n          \"colors\": [\"#ffa600\"]\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 105 Orange\",\n          \"colors\": [\"#ff7a00\"]\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 107 Light Rose\",\n          \"colors\": [\"#ff8d1f\"]\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 108 English Rose\",\n          \"colors\": [\"#ff9417\"]\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 109 Light Salmon\",\n          \"colors\": [\"#ff8a1f\"]\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 110 Middle Rose\",\n          \"colors\": [\"#d9821c\"]\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 111 Dark Pink\",\n          \"colors\": [\"#ff6d21\"]\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 113 Magenta\",\n          \"colors\": [\"#ff140f\"]\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 115 Peacock Blue\",\n          \"colors\": [\"#33ff33\"]\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 116 Med Blue Green\",\n          \"colors\": [\"#ceff38\"]\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 117 Steel Blue\",\n          \"colors\": [\"#ceff38\"]\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 118 Light Blue\",\n          \"colors\": [\"#4aff52\"]\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 119 Dark Blue\",\n          \"colors\": [\"#00baff\"]\n        },\n        {\n          \"dmxRange\": [131, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 121 Leaf Green\",\n          \"colors\": [\"#ceff00\"]\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 124 Dark Green\",\n          \"colors\": [\"#54ff0d\"]\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 126 Mauve\",\n          \"colors\": [\"#e32938\"]\n        },\n        {\n          \"dmxRange\": [138, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\",\n          \"colors\": [\"#ff3524\"]\n        },\n        {\n          \"dmxRange\": [142, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 132 Medium Blue\",\n          \"colors\": [\"#00ff8f\"]\n        },\n        {\n          \"dmxRange\": [145, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 135 Deep Golden Amber\",\n          \"colors\": [\"#ff3a00\"]\n        },\n        {\n          \"dmxRange\": [146, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 136 Pale Lavender\",\n          \"colors\": [\"#ffc53d\"]\n        },\n        {\n          \"dmxRange\": [147, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 137 Special Lavender\",\n          \"colors\": [\"#dbc54f\"]\n        },\n        {\n          \"dmxRange\": [149, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 139 Primary Green\",\n          \"colors\": [\"#4dff00\"]\n        },\n        {\n          \"dmxRange\": [151, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 141 Bright Blue\",\n          \"colors\": [\"#00ff57\"]\n        },\n        {\n          \"dmxRange\": [157, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 147 Apricot\",\n          \"colors\": [\"#ff8f0d\"]\n        },\n        {\n          \"dmxRange\": [162, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 152 Pale Gold\",\n          \"colors\": [\"#fdab1a\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 158 Deep Orange\",\n          \"colors\": [\"#de5400\"]\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 162 Bastard Amber\",\n          \"colors\": [\"#ffb51c\"]\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 164 Flame Red\",\n          \"colors\": [\"#ff2e02\"]\n        },\n        {\n          \"dmxRange\": [175, 178],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 165 Daylight Blue\",\n          \"colors\": [\"#52d65a\"]\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 169 Lilac Tint\",\n          \"colors\": [\"#ffc731\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 170 Deep Lavender\",\n          \"colors\": [\"#ffa840\"]\n        },\n        {\n          \"dmxRange\": [184, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 174 Dark Steel Blue\",\n          \"colors\": [\"#ffe756\"]\n        },\n        {\n          \"dmxRange\": [191, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 181 Congo Blue\",\n          \"colors\": [\"#4d00ff\"]\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 197 Alice Blue\",\n          \"colors\": [\"#80ff8f\"]\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dirty White\",\n          \"colors\": [\"#ffffbd\"]\n        },\n        {\n          \"dmxRange\": [209, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#fff5a1\"]\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"210deg\"\n      }\n    },\n    \"Maintenance\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan Tilt Fast (Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [25, 37],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan Tilt Normal\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [38, 42],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 1\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [43, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 2\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [48, 52],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 3 (Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [53, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve 4\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [58, 62],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW Gamma curve 1 – gamma = 1.0\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [63, 67],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW Gamma curve 2 – gamma = 1.5 (Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [68, 72],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW Gamma curve 3 – gamma = 2.0\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [73, 77],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation OFF (Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [78, 82],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 750 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [83, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 1000 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [88, 92],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 1200 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [93, 97],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 2000 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [98, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Halogen Lamp Simulation - Linear CTO @ 0 bit - 2500 W\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [103, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pixel map enabled\"\n        },\n        {\n          \"dmxRange\": [106, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 76],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom reset\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [77, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt reset\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Complete reset\",\n          \"hold\": \"5s\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"Zoom\",\n          \"angleStart\": \"4deg\",\n          \"angleEnd\": \"59.8deg\",\n          \"switchChannels\": {\n            \"Lens Rotation / Rotation Offset\": \"Lens Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Zoom\",\n          \"angle\": \"60deg\",\n          \"switchChannels\": {\n            \"Lens Rotation / Rotation Offset\": \"Lens Rotation Offset\"\n          }\n        }\n      ]\n    },\n    \"Lens Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"60deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"10rpm\",\n          \"speedEnd\": \"3rpm\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"-3rpm\",\n          \"speedEnd\": \"-10rpm\"\n        }\n      ]\n    },\n    \"Lens Rotation Offset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"4deg\",\n          \"comment\": \"Offset\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Rotation\",\n          \"angle\": \"0deg\",\n          \"comment\": \"Offset\"\n        }\n      ]\n    },\n    \"Shape Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single ring (ramp –/+)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Size Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Flash Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Filled rings (ramp –/+)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Size Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Flash Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open/Close 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Size Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Flash Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open/Close 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Size Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Flash Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random pixels 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Speed With Fade\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random pixels 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Speed With Fade\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Pixel Density\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow 1 (variable speed)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow 2 (variable color offset)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Color Offset\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fan\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bar 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Half moon\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Effect\",\n          \"effectName\": \"Triangle\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Segment 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"Arc 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Arc 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bar 2 (variable size)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random explosion\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Segment 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"X Bump\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"Image\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping section\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ramp by 6\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ramp by 4\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Left/right scrolling bar\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Up/down scrolling bar\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bar 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical arc 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical arc 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"Horizontal arc 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Horizontal arc 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mirrored pixel\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 4\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 5\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Semi arc (ramp –/+)\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping arc section\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel animation 6\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical ramp by 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Following pixel by 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"Syncopation\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [57, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [59, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bumping 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Macro Offset\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical pixel scrolling\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random vertical section\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random central section\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random ring 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random ring 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random ring 1+3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 66],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random ring 2+3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade\",\n            \"Shape Offset\": \"Shape Random Distribution\"\n          }\n        },\n        {\n          \"dmxRange\": [67, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single pixel ring 1\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Number of Rotating\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single pixel ring 2\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Number of Rotating\"\n          }\n        },\n        {\n          \"dmxRange\": [69, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single pixel ring 3\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Number of Rotating\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spiral\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Linear Fade and Wake Length\",\n            \"Shape Offset\": \"Shape Width\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Shape Speed\": \"Shape Rotation Speed\",\n            \"Shape Fade\": \"Shape Fade Gamma\",\n            \"Shape Offset\": \"Shape Angle Offset\"\n          }\n        }\n      ]\n    },\n    \"Shape Size Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\",\n          \"comment\": \"Radius size\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\",\n          \"comment\": \"Closing\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Opening\"\n        }\n      ]\n    },\n    \"Shape Speed With Fade\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"fade out\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"fade in/out\"\n        }\n      ]\n    },\n    \"Shape Rotation Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Shape Color Offset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [64, 158],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Shape Flash Distribution\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\",\n          \"comment\": \"Continuous flash distribution\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random flash distribution\"\n        }\n      ]\n    },\n    \"Shape Random Distribution\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": 2,\n        \"parameterEnd\": 20,\n        \"comment\": \"Pixels\"\n      }\n    },\n    \"Shape Pixel Density\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"helpWanted\": \"Is this the same as \\\"Shape Random Distribution\\\"?\"\n      }\n    },\n    \"Shape Angle Offset\": {\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Shape Width\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"Shape Macro Offset\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"Shape Number of Rotating\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\",\n        \"helpWanted\": \"What number is this? The number of rotating rings maybe?\"\n      }\n    },\n    \"Shape Fade Gamma\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Snap\"\n        },\n        {\n          \"dmxRange\": [16, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Smooth, fading curve gamma\",\n          \"parameterStart\": 0.5,\n          \"parameterEnd\": 2\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Smooth, fading curve with automatic gamma\"\n        }\n      ]\n    },\n    \"Shape Linear Fade\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\",\n        \"helpWanted\": \"Is this really a time unit? What is the difference to Shape Transition then?\"\n      }\n    },\n    \"Shape Linear Fade and Wake Length\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\",\n        \"helpWanted\": \"Is this really a time unit? What is the difference to Shape Transition then?\"\n      }\n    },\n    \"Shape Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Shape Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Shape Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Shape White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shape Transition\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Time\",\n          \"time\": \"instant\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Time\",\n          \"timeStart\": \"100ms\",\n          \"timeEnd\": \"4000ms\"\n        }\n      ]\n    },\n    \"Background Select\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No selection (wash)\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 2\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 3\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 4\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 2\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 2 + Ring 3\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 2 + Ring 3 + Ring 4\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 2 + Ring 3 + Ring 4\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 3 + Ring 4\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 4\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 2 + Ring 3\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 3\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ring 2 + Ring 4\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 3 + Ring 4\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pixel 1 + Ring 2 + Ring 4\"\n        },\n        {\n          \"dmxRange\": [24, 254],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No selection (wash)\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mirror effect\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red\": {\n      \"fineChannelAliases\": [\"$pixelKey Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"fineChannelAliases\": [\"$pixelKey Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"fineChannelAliases\": [\"$pixelKey Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"fineChannelAliases\": [\"$pixelKey White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Dimmer\": {\n      \"fineChannelAliases\": [\"$pixelKey Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"$pixelKey Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red LED $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green LED $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue LED $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White LED $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"channels\": [\n        \"Master Red\",\n        \"Master Red fine\",\n        \"Master Green\",\n        \"Master Green fine\",\n        \"Master Blue\",\n        \"Master Blue fine\",\n        \"Master White\",\n        \"Master White fine\",\n        \"Linear CTO\",\n        \"Color Presets\",\n        \"Master Strobe\",\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Maintenance\",\n        \"Reset\",\n        \"Zoom\",\n        \"Lens Rotation / Rotation Offset\"\n      ]\n    },\n    {\n      \"name\": \"Shapes\",\n      \"channels\": [\n        \"Master Red\",\n        \"Master Red fine\",\n        \"Master Green\",\n        \"Master Green fine\",\n        \"Master Blue\",\n        \"Master Blue fine\",\n        \"Master White\",\n        \"Master White fine\",\n        \"Linear CTO\",\n        \"Color Presets\",\n        \"Master Strobe\",\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Maintenance\",\n        \"Reset\",\n        \"Zoom\",\n        \"Lens Rotation / Rotation Offset\",\n        \"Shape Selection\",\n        \"Shape Speed\",\n        \"Shape Fade\",\n        \"Shape Red\",\n        \"Shape Green\",\n        \"Shape Blue\",\n        \"Shape White\",\n        \"Shape Dimmer\",\n        \"Background Dimmer\",\n        \"Shape Transition\",\n        \"Shape Offset\",\n        \"Foreground Strobe\",\n        \"Background Strobe\",\n        \"Background Select\"\n      ]\n    },\n    {\n      \"name\": \"Pixel RGB\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red LED $pixelKey\",\n            \"Green LED $pixelKey\",\n            \"Blue LED $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Pixel RGBW\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red LED $pixelKey\",\n            \"Green LED $pixelKey\",\n            \"Blue LED $pixelKey\",\n            \"White LED $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/clay-paky/alpha-spot-qwo-800.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Alpha Spot QWO 800\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-05-15\",\n    \"lastModifyDate\": \"2019-05-17\",\n    \"importPlugin\": {\n      \"plugin\": \"gdtf\",\n      \"date\": \"2018-09-11\",\n      \"comment\": \"GDTF fixture type ID: 00 1B 21 63 BA 95 00 00 8E 2D C1 C7 3A F9 7D 46\"\n    }\n  },\n  \"comment\": \"The ST version has a 6000K lamp.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.claypaky.it/media/documents/HR_AlphaSpotQWO800_and_ST_Manual_04.2016_EN.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=yNq1_7DnGjQ\",\n      \"https://www.youtube.com/watch?v=539x-P1G4Bo\",\n      \"https://www.youtube.com/watch?v=GHIqWbGhKKA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [385, 405, 650],\n    \"weight\": 30,\n    \"power\": 1200,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"MSR Platinum 35 discharge lamp\",\n      \"colorTemperature\": 7750,\n      \"lumens\": 54500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [11, 55]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ee262d\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#f1c136\"],\n          \"colorTemperature\": \"2600K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#08954d\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#87cf34\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#8566ba\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aquamarine\",\n          \"colors\": [\"#69c981\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#f47327\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#2e52ab\"]\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Animation Disk\": {\n      \"slots\": [\n        {\n          \"type\": \"AnimationGoboStart\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Cyan\": {\n      \"defaultValue\": 255,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 255,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 255,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"default\",\n        \"colorTemperatureEnd\": \"CTO\"\n      }\n    },\n    \"Color Wheel\": {\n      \"highlightValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [121, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"-5rpm\",\n          \"speedEnd\": \"0rpm\",\n          \"helpWanted\": \"Can the color wheel rotate in both directions? The manual only mentions slow to fast rotation in the DMX range 128…255. The capabilities here were imported from the GDTF file and manually edited instead.\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"5rpm\",\n          \"speedEnd\": \"0rpm\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"highlightValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Random Macro Color (only for Macro Effects)\"\n        },\n        {\n          \"dmxRange\": [2, 3],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6b0ab\"],\n          \"comment\": \"Med Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e0dc00\"],\n          \"comment\": \"Med Yellow\"\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b40000\"],\n          \"comment\": \"Bright Red\"\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6c1cbe\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8eb4dd\"],\n          \"comment\": \"Pale Blue\"\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0060cd\"],\n          \"comment\": \"Sky Blue\"\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Tokyo Blue\"\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002cbd\"],\n          \"comment\": \"Just Blue\"\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#9ed64d\"],\n          \"comment\": \"Lime Green\"\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#006d21\"],\n          \"comment\": \"Dark Yellow Green\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d6dc2d\"],\n          \"comment\": \"Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e8d100\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f1c45b\"],\n          \"comment\": \"Light Amber\"\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d7d1b9\"],\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f7af00\"],\n          \"comment\": \"Deep Amber\"\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ef7f00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b70000\"],\n          \"comment\": \"Primary Red\"\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f980a9\"],\n          \"comment\": \"Light Rose\"\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#eda18e\"],\n          \"comment\": \"English Rose\"\n        },\n        {\n          \"dmxRange\": [40, 41],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f892b1\"],\n          \"comment\": \"Light Salmon\"\n        },\n        {\n          \"dmxRange\": [42, 43],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ec47b6\"],\n          \"comment\": \"Dark Pink\"\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00afbe\"],\n          \"comment\": \"Peacock Blue\"\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#008192\"],\n          \"comment\": \"Medium Blue Green\"\n        },\n        {\n          \"dmxRange\": [48, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#53bddf\"],\n          \"comment\": \"Steel Blue\"\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#003987\"],\n          \"comment\": \"Light Blue\"\n        },\n        {\n          \"dmxRange\": [52, 53],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000a8\"],\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#100092\"],\n          \"comment\": \"Deep Blue\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#53d655\"],\n          \"comment\": \"Leaf Green\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00cb60\"],\n          \"comment\": \"Fern Green\"\n        },\n        {\n          \"dmxRange\": [60, 61],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7e008f\"],\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [62, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cc009e\"],\n          \"comment\": \"Bright Pink\"\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00b0bd\"],\n          \"comment\": \"Marine Blue\"\n        },\n        {\n          \"dmxRange\": [66, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#004eb6\"],\n          \"comment\": \"Medium Blue\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e57852\"],\n          \"comment\": \"Golden Amber\"\n        },\n        {\n          \"dmxRange\": [70, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e30000\"],\n          \"comment\": \"Deep Golden Amber\"\n        },\n        {\n          \"dmxRange\": [72, 73],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#af95cb\"],\n          \"comment\": \"Pale Lavender\"\n        },\n        {\n          \"dmxRange\": [74, 75],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8472db\"],\n          \"comment\": \"Special Lavender\"\n        },\n        {\n          \"dmxRange\": [76, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#afdc8f\"],\n          \"comment\": \"Pale Green\"\n        },\n        {\n          \"dmxRange\": [78, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#53d655\"],\n          \"comment\": \"Light Green\"\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#007100\"],\n          \"comment\": \"Primary Green\"\n        },\n        {\n          \"dmxRange\": [82, 83],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#007ad1\"],\n          \"comment\": \"Bright Blue\"\n        },\n        {\n          \"dmxRange\": [84, 85],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#eb9b6f\"],\n          \"comment\": \"Apricot\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bd006b\"],\n          \"comment\": \"Bright Rose\"\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2b6b4\"],\n          \"comment\": \"Pale Gold\"\n        },\n        {\n          \"dmxRange\": [90, 91],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2b6b4\"],\n          \"comment\": \"Pale Rose\"\n        },\n        {\n          \"dmxRange\": [92, 93],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f95891\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [94, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#df6300\"],\n          \"comment\": \"Deep Orange\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#edc3c4\"],\n          \"comment\": \"Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [98, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e2001f\"],\n          \"comment\": \"Flame Red\"\n        },\n        {\n          \"dmxRange\": [100, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0077d8\"],\n          \"comment\": \"Daylight Blue\"\n        },\n        {\n          \"dmxRange\": [102, 103],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#beb1d6\"],\n          \"comment\": \"Lilac Tint\"\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#996ebb\"],\n          \"comment\": \"Deep Lavender\"\n        },\n        {\n          \"dmxRange\": [106, 107],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0092c8\"],\n          \"comment\": \"Lagoon Blue\"\n        },\n        {\n          \"dmxRange\": [108, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f09e00\"],\n          \"comment\": \"Chrome Orange\"\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6000c5\"],\n          \"comment\": \"Dark Lavender\"\n        },\n        {\n          \"dmxRange\": [112, 113],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Congo Blue\"\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#004fbf\"],\n          \"comment\": \"Alice Blue\"\n        },\n        {\n          \"dmxRange\": [116, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6a92cd\"],\n          \"comment\": \"Full CTB\"\n        },\n        {\n          \"dmxRange\": [118, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#99b2db\"],\n          \"comment\": \"1/2 CTB\"\n        },\n        {\n          \"dmxRange\": [120, 121],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bac3de\"],\n          \"comment\": \"1/4 CTB\"\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e7a36d\"],\n          \"comment\": \"Full CTO (Full CT Orange)\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e5bda0\"],\n          \"comment\": \"1/2 CTO\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6c8bf\"],\n          \"comment\": \"1/4 CTO\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d8a5ce\"],\n          \"comment\": \"Minus Green\"\n        },\n        {\n          \"dmxRange\": [130, 131],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dcbdd8\"],\n          \"comment\": \"Half Minus Green\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#79a7d7\"],\n          \"comment\": \"3/4 CTB\"\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#deb182\"],\n          \"comment\": \"3/4 CTO\"\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00a796\"],\n          \"comment\": \"Jade\"\n        },\n        {\n          \"dmxRange\": [138, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#53d655\"],\n          \"comment\": \"Mallard Green\"\n        },\n        {\n          \"dmxRange\": [140, 141],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#854bb8\"],\n          \"comment\": \"Fuchsia Pink\"\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0083cf\"],\n          \"comment\": \"Glacier BLue (Glacier Blue)\"\n        },\n        {\n          \"dmxRange\": [144, 145],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00aadc\"],\n          \"comment\": \"Lighter Blue\"\n        },\n        {\n          \"dmxRange\": [146, 147],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ddc29a\"],\n          \"comment\": \"Half CT Straw\"\n        },\n        {\n          \"dmxRange\": [148, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 104,\n      \"highlightValue\": 104,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"12Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Iris\": {\n      \"defaultValue\": 128,\n      \"highlightValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 131],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"closed\",\n          \"openPercentEnd\": \"open\"\n        },\n        {\n          \"dmxRange\": [132, 171],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Strobe\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [172, 211],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"RampDown\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [212, 251],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"RampUp\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"highlightValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 113],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"-100rpm\",\n          \"speedEnd\": \"-5rpm\"\n        },\n        {\n          \"dmxRange\": [114, 117],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [118, 159],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"5rpm\",\n          \"speedEnd\": \"100rpm\"\n        },\n        {\n          \"dmxRange\": [160, 171],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [172, 183],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [184, 195],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [196, 207],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [208, 219],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [220, 231],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [232, 243],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [244, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"highlightValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [17, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [33, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [49, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [65, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [82, 97],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [98, 113],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [114, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [130, 147],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [148, 165],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [166, 183],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [184, 201],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [202, 219],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [220, 237],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [1, 20],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"90deg\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"90deg\"\n        },\n        {\n          \"dmxRange\": [22, 41],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"90deg\",\n          \"angleEnd\": \"180deg\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"180deg\"\n        },\n        {\n          \"dmxRange\": [43, 62],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"180deg\",\n          \"angleEnd\": \"270deg\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"270deg\"\n        },\n        {\n          \"dmxRange\": [64, 83],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"270deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [85, 104],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"360deg\",\n          \"angleEnd\": \"450deg\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"450deg\"\n        },\n        {\n          \"dmxRange\": [106, 126],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"450deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"180rpm\",\n          \"speedEnd\": \"0.0367rpm\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"-0.0367rpm\",\n          \"speedEnd\": \"-180rpm\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3 facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [1, 20],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"90deg\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"90deg\"\n        },\n        {\n          \"dmxRange\": [22, 41],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"90deg\",\n          \"angleEnd\": \"180deg\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"180deg\"\n        },\n        {\n          \"dmxRange\": [43, 62],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"180deg\",\n          \"angleEnd\": \"270deg\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"270deg\"\n        },\n        {\n          \"dmxRange\": [64, 83],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"270deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [85, 104],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"360deg\",\n          \"angleEnd\": \"450deg\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"450deg\"\n        },\n        {\n          \"dmxRange\": [106, 126],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"450deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"-120rpm\",\n          \"speedEnd\": \"-0.05rpm\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"0.05rpm\",\n          \"speedEnd\": \"120rpm\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"0%\",\n        \"frostIntensityEnd\": \"100%\"\n      }\n    },\n    \"Animation Disk\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Animation Disk insertion\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"Animation Disk Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 124],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Disk\",\n          \"speedStart\": \"-120rpm\",\n          \"speedEnd\": \"-0.0733rpm\"\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Disk\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [126, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Disk\",\n          \"speedStart\": \"0.0733rpm\",\n          \"speedEnd\": \"120rpm\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"11deg\",\n        \"angleEnd\": \"55deg\",\n        \"helpWanted\": \"The manual specifies this capability as wide…narrow, the GDTF as narrow…wide (with the given angles). Which one is correct?\"\n      }\n    },\n    \"Autofocus Distance\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Autofocus off\"\n        },\n        {\n          \"dmxRange\": [7, 9],\n          \"type\": \"Focus\",\n          \"distance\": \"3m\"\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"Focus\",\n          \"distance\": \"4m\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"Focus\",\n          \"distance\": \"5m\"\n        },\n        {\n          \"dmxRange\": [15, 17],\n          \"type\": \"Focus\",\n          \"distance\": \"6m\"\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"Focus\",\n          \"distance\": \"7m\"\n        },\n        {\n          \"dmxRange\": [20, 22],\n          \"type\": \"Focus\",\n          \"distance\": \"8m\"\n        },\n        {\n          \"dmxRange\": [23, 25],\n          \"type\": \"Focus\",\n          \"distance\": \"9m\"\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"Focus\",\n          \"distance\": \"10m\"\n        },\n        {\n          \"dmxRange\": [28, 255],\n          \"type\": \"Focus\",\n          \"distanceStart\": \"10m\",\n          \"distanceEnd\": \"100m\"\n        }\n      ]\n    },\n    \"Autofocus Adjust\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Focus\",\n          \"distanceStart\": \"-100%\",\n          \"distanceEnd\": \"0%\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Focus\",\n          \"distance\": \"0%\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Focus\",\n          \"distanceStart\": \"0%\",\n          \"distanceEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Macro off\"\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Stand by\"\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Stand by black\"\n        },\n        {\n          \"dmxRange\": [16, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [28, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [40, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [52, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [64, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [76, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [88, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [100, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [112, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Stand by black\"\n        },\n        {\n          \"dmxRange\": [136, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro 1\"\n        },\n        {\n          \"dmxRange\": [148, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro 2\"\n        },\n        {\n          \"dmxRange\": [160, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro 3\"\n        },\n        {\n          \"dmxRange\": [172, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro 4\"\n        },\n        {\n          \"dmxRange\": [184, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro 5\"\n        },\n        {\n          \"dmxRange\": [196, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro 6\"\n        },\n        {\n          \"dmxRange\": [208, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro 7\"\n        },\n        {\n          \"dmxRange\": [220, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro 8\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Stand by black\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"250deg\"\n      }\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan Tilt Fast\"\n        },\n        {\n          \"dmxRange\": [25, 37],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan Tilt Normal\"\n        },\n        {\n          \"dmxRange\": [38, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve Conventional\"\n        },\n        {\n          \"dmxRange\": [51, 62],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve Linear\"\n        },\n        {\n          \"dmxRange\": [63, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 76],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Effects Reset\"\n        },\n        {\n          \"dmxRange\": [77, 127],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan/Tilt Reset\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Complete Reset\"\n        }\n      ]\n    },\n    \"Lamp Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 100],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Lamp Off\"\n        },\n        {\n          \"dmxRange\": [101, 179],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [180, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Lamp On\"\n        }\n      ]\n    },\n    \"Pan/Tilt Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"0s\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"0.2s\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"0.4s\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"0.6s\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"0.8s\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"1s\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"1.2s\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"1.4s\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"1.6s\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"1.8s\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"2s\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"2.2s\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"2.4s\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"2.6s\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"2.8s\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"3s\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"3.2s\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"3.4s\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"3.6s\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"3.8s\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"4s\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"4.2s\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"4.4s\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"4.6s\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"4.8s\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"5s\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"5.2s\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"5.4s\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"5.6s\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"5.8s\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"6s\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"6.2s\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"6.4s\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"6.6s\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"6.8s\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"7s\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"7.2s\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"7.4s\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"7.6s\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"7.8s\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"8s\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"8.2s\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"8.4s\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"8.6s\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"8.8s\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"9s\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"9.2s\"\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"9.4s\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"9.6s\"\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"9.8s\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"10s\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"10.2s\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"10.4s\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"10.6s\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"11s\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"12s\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"13s\"\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"14s\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"15s\"\n        },\n        {\n          \"dmxRange\": [65, 67],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"16s\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"17s\"\n        },\n        {\n          \"dmxRange\": [70, 72],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"18s\"\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"19s\"\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"20s\"\n        },\n        {\n          \"dmxRange\": [78, 80],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"21s\"\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"22s\"\n        },\n        {\n          \"dmxRange\": [83, 85],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"23s\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"24s\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"25s\"\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"26s\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"27s\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"28s\"\n        },\n        {\n          \"dmxRange\": [98, 100],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"29s\"\n        },\n        {\n          \"dmxRange\": [101, 103],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"30s\"\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"31s\"\n        },\n        {\n          \"dmxRange\": [106, 108],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"32s\"\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"33s\"\n        },\n        {\n          \"dmxRange\": [111, 113],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"34s\"\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"35s\"\n        },\n        {\n          \"dmxRange\": [116, 118],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"36s\"\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"37s\"\n        },\n        {\n          \"dmxRange\": [121, 123],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"38s\"\n        },\n        {\n          \"dmxRange\": [124, 126],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"39s\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"40s\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"41s\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"42s\"\n        },\n        {\n          \"dmxRange\": [134, 136],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"43s\"\n        },\n        {\n          \"dmxRange\": [137, 138],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"44s\"\n        },\n        {\n          \"dmxRange\": [139, 141],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"45s\"\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"46s\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"47s\"\n        },\n        {\n          \"dmxRange\": [147, 148],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"48s\"\n        },\n        {\n          \"dmxRange\": [149, 151],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"49s\"\n        },\n        {\n          \"dmxRange\": [152, 154],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"50s\"\n        },\n        {\n          \"dmxRange\": [155, 156],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"51s\"\n        },\n        {\n          \"dmxRange\": [157, 159],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"52s\"\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"53s\"\n        },\n        {\n          \"dmxRange\": [162, 164],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"54s\"\n        },\n        {\n          \"dmxRange\": [165, 166],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"55s\"\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"56s\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"57s\"\n        },\n        {\n          \"dmxRange\": [172, 174],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"58s\"\n        },\n        {\n          \"dmxRange\": [175, 177],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"59s\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"60s\"\n        },\n        {\n          \"dmxRange\": [180, 182],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"65s\"\n        },\n        {\n          \"dmxRange\": [183, 184],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"70s\"\n        },\n        {\n          \"dmxRange\": [185, 187],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"75s\"\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"80s\"\n        },\n        {\n          \"dmxRange\": [190, 192],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"85s\"\n        },\n        {\n          \"dmxRange\": [193, 194],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"90s\"\n        },\n        {\n          \"dmxRange\": [195, 197],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"95s\"\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"100s\"\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"110s\"\n        },\n        {\n          \"dmxRange\": [203, 205],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"120s\"\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"130s\"\n        },\n        {\n          \"dmxRange\": [208, 210],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"140s\"\n        },\n        {\n          \"dmxRange\": [211, 212],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"150s\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"160s\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"170s\"\n        },\n        {\n          \"dmxRange\": [218, 220],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"180s\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"190s\"\n        },\n        {\n          \"dmxRange\": [223, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"200s\"\n        },\n        {\n          \"dmxRange\": [226, 228],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"210s\"\n        },\n        {\n          \"dmxRange\": [229, 230],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"220s\"\n        },\n        {\n          \"dmxRange\": [231, 233],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"230s\"\n        },\n        {\n          \"dmxRange\": [234, 235],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"240s\"\n        },\n        {\n          \"dmxRange\": [236, 238],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"250s\"\n        },\n        {\n          \"dmxRange\": [239, 240],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"260s\"\n        },\n        {\n          \"dmxRange\": [241, 243],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"270s\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"280s\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"290s\"\n        },\n        {\n          \"dmxRange\": [249, 250],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"300s\"\n        },\n        {\n          \"dmxRange\": [251, 254],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"310s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow cue Data\"\n        }\n      ]\n    },\n    \"Color Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Time\",\n          \"time\": \"0s\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Time\",\n          \"time\": \"0.2s\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Time\",\n          \"time\": \"0.4s\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Time\",\n          \"time\": \"0.6s\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Time\",\n          \"time\": \"0.8s\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Time\",\n          \"time\": \"1s\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Time\",\n          \"time\": \"1.2s\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Time\",\n          \"time\": \"1.4s\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Time\",\n          \"time\": \"1.6s\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Time\",\n          \"time\": \"1.8s\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Time\",\n          \"time\": \"2s\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Time\",\n          \"time\": \"2.2s\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Time\",\n          \"time\": \"2.4s\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Time\",\n          \"time\": \"2.6s\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Time\",\n          \"time\": \"2.8s\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Time\",\n          \"time\": \"3s\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Time\",\n          \"time\": \"3.2s\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Time\",\n          \"time\": \"3.4s\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Time\",\n          \"time\": \"3.6s\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Time\",\n          \"time\": \"3.8s\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Time\",\n          \"time\": \"4s\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Time\",\n          \"time\": \"4.2s\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Time\",\n          \"time\": \"4.4s\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Time\",\n          \"time\": \"4.6s\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Time\",\n          \"time\": \"4.8s\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Time\",\n          \"time\": \"5s\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Time\",\n          \"time\": \"5.2s\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Time\",\n          \"time\": \"5.4s\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Time\",\n          \"time\": \"5.6s\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Time\",\n          \"time\": \"5.8s\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Time\",\n          \"time\": \"6s\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Time\",\n          \"time\": \"6.2s\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Time\",\n          \"time\": \"6.4s\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Time\",\n          \"time\": \"6.6s\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Time\",\n          \"time\": \"6.8s\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Time\",\n          \"time\": \"7s\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Time\",\n          \"time\": \"7.2s\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Time\",\n          \"time\": \"7.4s\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Time\",\n          \"time\": \"7.6s\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Time\",\n          \"time\": \"7.8s\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Time\",\n          \"time\": \"8s\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Time\",\n          \"time\": \"8.2s\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Time\",\n          \"time\": \"8.4s\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"Time\",\n          \"time\": \"8.6s\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Time\",\n          \"time\": \"8.8s\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Time\",\n          \"time\": \"9s\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Time\",\n          \"time\": \"9.2s\"\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Time\",\n          \"time\": \"9.4s\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Time\",\n          \"time\": \"9.6s\"\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Time\",\n          \"time\": \"9.8s\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Time\",\n          \"time\": \"10s\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Time\",\n          \"time\": \"10.2s\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Time\",\n          \"time\": \"10.4s\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Time\",\n          \"time\": \"10.6s\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"Time\",\n          \"time\": \"11s\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"Time\",\n          \"time\": \"12s\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"Time\",\n          \"time\": \"13s\"\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"Time\",\n          \"time\": \"14s\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"Time\",\n          \"time\": \"15s\"\n        },\n        {\n          \"dmxRange\": [65, 67],\n          \"type\": \"Time\",\n          \"time\": \"16s\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"Time\",\n          \"time\": \"17s\"\n        },\n        {\n          \"dmxRange\": [70, 72],\n          \"type\": \"Time\",\n          \"time\": \"18s\"\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"Time\",\n          \"time\": \"19s\"\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"Time\",\n          \"time\": \"20s\"\n        },\n        {\n          \"dmxRange\": [78, 80],\n          \"type\": \"Time\",\n          \"time\": \"21s\"\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"Time\",\n          \"time\": \"22s\"\n        },\n        {\n          \"dmxRange\": [83, 85],\n          \"type\": \"Time\",\n          \"time\": \"23s\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"Time\",\n          \"time\": \"24s\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Time\",\n          \"time\": \"25s\"\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"Time\",\n          \"time\": \"26s\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Time\",\n          \"time\": \"27s\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"Time\",\n          \"time\": \"28s\"\n        },\n        {\n          \"dmxRange\": [98, 100],\n          \"type\": \"Time\",\n          \"time\": \"29s\"\n        },\n        {\n          \"dmxRange\": [101, 103],\n          \"type\": \"Time\",\n          \"time\": \"30s\"\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"Time\",\n          \"time\": \"31s\"\n        },\n        {\n          \"dmxRange\": [106, 108],\n          \"type\": \"Time\",\n          \"time\": \"32s\"\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"Time\",\n          \"time\": \"33s\"\n        },\n        {\n          \"dmxRange\": [111, 113],\n          \"type\": \"Time\",\n          \"time\": \"34s\"\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"Time\",\n          \"time\": \"35s\"\n        },\n        {\n          \"dmxRange\": [116, 118],\n          \"type\": \"Time\",\n          \"time\": \"36s\"\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"Time\",\n          \"time\": \"37s\"\n        },\n        {\n          \"dmxRange\": [121, 123],\n          \"type\": \"Time\",\n          \"time\": \"38s\"\n        },\n        {\n          \"dmxRange\": [124, 126],\n          \"type\": \"Time\",\n          \"time\": \"39s\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"Time\",\n          \"time\": \"40s\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Time\",\n          \"time\": \"41s\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"Time\",\n          \"time\": \"42s\"\n        },\n        {\n          \"dmxRange\": [134, 136],\n          \"type\": \"Time\",\n          \"time\": \"43s\"\n        },\n        {\n          \"dmxRange\": [137, 138],\n          \"type\": \"Time\",\n          \"time\": \"44s\"\n        },\n        {\n          \"dmxRange\": [139, 141],\n          \"type\": \"Time\",\n          \"time\": \"45s\"\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"Time\",\n          \"time\": \"46s\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"Time\",\n          \"time\": \"47s\"\n        },\n        {\n          \"dmxRange\": [147, 148],\n          \"type\": \"Time\",\n          \"time\": \"48s\"\n        },\n        {\n          \"dmxRange\": [149, 151],\n          \"type\": \"Time\",\n          \"time\": \"49s\"\n        },\n        {\n          \"dmxRange\": [152, 154],\n          \"type\": \"Time\",\n          \"time\": \"50s\"\n        },\n        {\n          \"dmxRange\": [155, 156],\n          \"type\": \"Time\",\n          \"time\": \"51s\"\n        },\n        {\n          \"dmxRange\": [157, 159],\n          \"type\": \"Time\",\n          \"time\": \"52s\"\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"Time\",\n          \"time\": \"53s\"\n        },\n        {\n          \"dmxRange\": [162, 164],\n          \"type\": \"Time\",\n          \"time\": \"54s\"\n        },\n        {\n          \"dmxRange\": [165, 166],\n          \"type\": \"Time\",\n          \"time\": \"55s\"\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"Time\",\n          \"time\": \"56s\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Time\",\n          \"time\": \"57s\"\n        },\n        {\n          \"dmxRange\": [172, 174],\n          \"type\": \"Time\",\n          \"time\": \"58s\"\n        },\n        {\n          \"dmxRange\": [175, 177],\n          \"type\": \"Time\",\n          \"time\": \"59s\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"Time\",\n          \"time\": \"60s\"\n        },\n        {\n          \"dmxRange\": [180, 182],\n          \"type\": \"Time\",\n          \"time\": \"65s\"\n        },\n        {\n          \"dmxRange\": [183, 184],\n          \"type\": \"Time\",\n          \"time\": \"70s\"\n        },\n        {\n          \"dmxRange\": [185, 187],\n          \"type\": \"Time\",\n          \"time\": \"75s\"\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"Time\",\n          \"time\": \"80s\"\n        },\n        {\n          \"dmxRange\": [190, 192],\n          \"type\": \"Time\",\n          \"time\": \"85s\"\n        },\n        {\n          \"dmxRange\": [193, 194],\n          \"type\": \"Time\",\n          \"time\": \"90s\"\n        },\n        {\n          \"dmxRange\": [195, 197],\n          \"type\": \"Time\",\n          \"time\": \"95s\"\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"Time\",\n          \"time\": \"100s\"\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"Time\",\n          \"time\": \"110s\"\n        },\n        {\n          \"dmxRange\": [203, 205],\n          \"type\": \"Time\",\n          \"time\": \"120s\"\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"Time\",\n          \"time\": \"130s\"\n        },\n        {\n          \"dmxRange\": [208, 210],\n          \"type\": \"Time\",\n          \"time\": \"140s\"\n        },\n        {\n          \"dmxRange\": [211, 212],\n          \"type\": \"Time\",\n          \"time\": \"150s\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"Time\",\n          \"time\": \"160s\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"Time\",\n          \"time\": \"170s\"\n        },\n        {\n          \"dmxRange\": [218, 220],\n          \"type\": \"Time\",\n          \"time\": \"180s\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"Time\",\n          \"time\": \"190s\"\n        },\n        {\n          \"dmxRange\": [223, 225],\n          \"type\": \"Time\",\n          \"time\": \"200s\"\n        },\n        {\n          \"dmxRange\": [226, 228],\n          \"type\": \"Time\",\n          \"time\": \"210s\"\n        },\n        {\n          \"dmxRange\": [229, 230],\n          \"type\": \"Time\",\n          \"time\": \"220s\"\n        },\n        {\n          \"dmxRange\": [231, 233],\n          \"type\": \"Time\",\n          \"time\": \"230s\"\n        },\n        {\n          \"dmxRange\": [234, 235],\n          \"type\": \"Time\",\n          \"time\": \"240s\"\n        },\n        {\n          \"dmxRange\": [236, 238],\n          \"type\": \"Time\",\n          \"time\": \"250s\"\n        },\n        {\n          \"dmxRange\": [239, 240],\n          \"type\": \"Time\",\n          \"time\": \"260s\"\n        },\n        {\n          \"dmxRange\": [241, 243],\n          \"type\": \"Time\",\n          \"time\": \"270s\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"Time\",\n          \"time\": \"280s\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Time\",\n          \"time\": \"290s\"\n        },\n        {\n          \"dmxRange\": [249, 250],\n          \"type\": \"Time\",\n          \"time\": \"300s\"\n        },\n        {\n          \"dmxRange\": [251, 254],\n          \"type\": \"Time\",\n          \"time\": \"310s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow cue Data\"\n        }\n      ]\n    },\n    \"Beam Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Time\",\n          \"time\": \"0s\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Time\",\n          \"time\": \"0.2s\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Time\",\n          \"time\": \"0.4s\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Time\",\n          \"time\": \"0.6s\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Time\",\n          \"time\": \"0.8s\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Time\",\n          \"time\": \"1s\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Time\",\n          \"time\": \"1.2s\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Time\",\n          \"time\": \"1.4s\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Time\",\n          \"time\": \"1.6s\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Time\",\n          \"time\": \"1.8s\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Time\",\n          \"time\": \"2s\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Time\",\n          \"time\": \"2.2s\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Time\",\n          \"time\": \"2.4s\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Time\",\n          \"time\": \"2.6s\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Time\",\n          \"time\": \"2.8s\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Time\",\n          \"time\": \"3s\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Time\",\n          \"time\": \"3.2s\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Time\",\n          \"time\": \"3.4s\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Time\",\n          \"time\": \"3.6s\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Time\",\n          \"time\": \"3.8s\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Time\",\n          \"time\": \"4s\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Time\",\n          \"time\": \"4.2s\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Time\",\n          \"time\": \"4.4s\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Time\",\n          \"time\": \"4.6s\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Time\",\n          \"time\": \"4.8s\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Time\",\n          \"time\": \"5s\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Time\",\n          \"time\": \"5.2s\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Time\",\n          \"time\": \"5.4s\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Time\",\n          \"time\": \"5.6s\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Time\",\n          \"time\": \"5.8s\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Time\",\n          \"time\": \"6s\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Time\",\n          \"time\": \"6.2s\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Time\",\n          \"time\": \"6.4s\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Time\",\n          \"time\": \"6.6s\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Time\",\n          \"time\": \"6.8s\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Time\",\n          \"time\": \"7s\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Time\",\n          \"time\": \"7.2s\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Time\",\n          \"time\": \"7.4s\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Time\",\n          \"time\": \"7.6s\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Time\",\n          \"time\": \"7.8s\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Time\",\n          \"time\": \"8s\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Time\",\n          \"time\": \"8.2s\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Time\",\n          \"time\": \"8.4s\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"Time\",\n          \"time\": \"8.6s\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Time\",\n          \"time\": \"8.8s\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Time\",\n          \"time\": \"9s\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Time\",\n          \"time\": \"9.2s\"\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Time\",\n          \"time\": \"9.4s\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Time\",\n          \"time\": \"9.6s\"\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Time\",\n          \"time\": \"9.8s\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Time\",\n          \"time\": \"10s\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Time\",\n          \"time\": \"10.2s\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Time\",\n          \"time\": \"10.4s\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Time\",\n          \"time\": \"10.6s\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"Time\",\n          \"time\": \"11s\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"Time\",\n          \"time\": \"12s\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"Time\",\n          \"time\": \"13s\"\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"Time\",\n          \"time\": \"14s\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"Time\",\n          \"time\": \"15s\"\n        },\n        {\n          \"dmxRange\": [65, 67],\n          \"type\": \"Time\",\n          \"time\": \"16s\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"Time\",\n          \"time\": \"17s\"\n        },\n        {\n          \"dmxRange\": [70, 72],\n          \"type\": \"Time\",\n          \"time\": \"18s\"\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"Time\",\n          \"time\": \"19s\"\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"Time\",\n          \"time\": \"20s\"\n        },\n        {\n          \"dmxRange\": [78, 80],\n          \"type\": \"Time\",\n          \"time\": \"21s\"\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"Time\",\n          \"time\": \"22s\"\n        },\n        {\n          \"dmxRange\": [83, 85],\n          \"type\": \"Time\",\n          \"time\": \"23s\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"Time\",\n          \"time\": \"24s\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Time\",\n          \"time\": \"25s\"\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"Time\",\n          \"time\": \"26s\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Time\",\n          \"time\": \"27s\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"Time\",\n          \"time\": \"28s\"\n        },\n        {\n          \"dmxRange\": [98, 100],\n          \"type\": \"Time\",\n          \"time\": \"29s\"\n        },\n        {\n          \"dmxRange\": [101, 103],\n          \"type\": \"Time\",\n          \"time\": \"30s\"\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"Time\",\n          \"time\": \"31s\"\n        },\n        {\n          \"dmxRange\": [106, 108],\n          \"type\": \"Time\",\n          \"time\": \"32s\"\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"Time\",\n          \"time\": \"33s\"\n        },\n        {\n          \"dmxRange\": [111, 113],\n          \"type\": \"Time\",\n          \"time\": \"34s\"\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"Time\",\n          \"time\": \"35s\"\n        },\n        {\n          \"dmxRange\": [116, 118],\n          \"type\": \"Time\",\n          \"time\": \"36s\"\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"Time\",\n          \"time\": \"37s\"\n        },\n        {\n          \"dmxRange\": [121, 123],\n          \"type\": \"Time\",\n          \"time\": \"38s\"\n        },\n        {\n          \"dmxRange\": [124, 126],\n          \"type\": \"Time\",\n          \"time\": \"39s\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"Time\",\n          \"time\": \"40s\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Time\",\n          \"time\": \"41s\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"Time\",\n          \"time\": \"42s\"\n        },\n        {\n          \"dmxRange\": [134, 136],\n          \"type\": \"Time\",\n          \"time\": \"43s\"\n        },\n        {\n          \"dmxRange\": [137, 138],\n          \"type\": \"Time\",\n          \"time\": \"44s\"\n        },\n        {\n          \"dmxRange\": [139, 141],\n          \"type\": \"Time\",\n          \"time\": \"45s\"\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"Time\",\n          \"time\": \"46s\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"Time\",\n          \"time\": \"47s\"\n        },\n        {\n          \"dmxRange\": [147, 148],\n          \"type\": \"Time\",\n          \"time\": \"48s\"\n        },\n        {\n          \"dmxRange\": [149, 151],\n          \"type\": \"Time\",\n          \"time\": \"49s\"\n        },\n        {\n          \"dmxRange\": [152, 154],\n          \"type\": \"Time\",\n          \"time\": \"50s\"\n        },\n        {\n          \"dmxRange\": [155, 156],\n          \"type\": \"Time\",\n          \"time\": \"51s\"\n        },\n        {\n          \"dmxRange\": [157, 159],\n          \"type\": \"Time\",\n          \"time\": \"52s\"\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"Time\",\n          \"time\": \"53s\"\n        },\n        {\n          \"dmxRange\": [162, 164],\n          \"type\": \"Time\",\n          \"time\": \"54s\"\n        },\n        {\n          \"dmxRange\": [165, 166],\n          \"type\": \"Time\",\n          \"time\": \"55s\"\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"Time\",\n          \"time\": \"56s\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Time\",\n          \"time\": \"57s\"\n        },\n        {\n          \"dmxRange\": [172, 174],\n          \"type\": \"Time\",\n          \"time\": \"58s\"\n        },\n        {\n          \"dmxRange\": [175, 177],\n          \"type\": \"Time\",\n          \"time\": \"59s\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"Time\",\n          \"time\": \"60s\"\n        },\n        {\n          \"dmxRange\": [180, 182],\n          \"type\": \"Time\",\n          \"time\": \"65s\"\n        },\n        {\n          \"dmxRange\": [183, 184],\n          \"type\": \"Time\",\n          \"time\": \"70s\"\n        },\n        {\n          \"dmxRange\": [185, 187],\n          \"type\": \"Time\",\n          \"time\": \"75s\"\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"Time\",\n          \"time\": \"80s\"\n        },\n        {\n          \"dmxRange\": [190, 192],\n          \"type\": \"Time\",\n          \"time\": \"85s\"\n        },\n        {\n          \"dmxRange\": [193, 194],\n          \"type\": \"Time\",\n          \"time\": \"90s\"\n        },\n        {\n          \"dmxRange\": [195, 197],\n          \"type\": \"Time\",\n          \"time\": \"95s\"\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"Time\",\n          \"time\": \"100s\"\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"Time\",\n          \"time\": \"110s\"\n        },\n        {\n          \"dmxRange\": [203, 205],\n          \"type\": \"Time\",\n          \"time\": \"120s\"\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"Time\",\n          \"time\": \"130s\"\n        },\n        {\n          \"dmxRange\": [208, 210],\n          \"type\": \"Time\",\n          \"time\": \"140s\"\n        },\n        {\n          \"dmxRange\": [211, 212],\n          \"type\": \"Time\",\n          \"time\": \"150s\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"Time\",\n          \"time\": \"160s\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"Time\",\n          \"time\": \"170s\"\n        },\n        {\n          \"dmxRange\": [218, 220],\n          \"type\": \"Time\",\n          \"time\": \"180s\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"Time\",\n          \"time\": \"190s\"\n        },\n        {\n          \"dmxRange\": [223, 225],\n          \"type\": \"Time\",\n          \"time\": \"200s\"\n        },\n        {\n          \"dmxRange\": [226, 228],\n          \"type\": \"Time\",\n          \"time\": \"210s\"\n        },\n        {\n          \"dmxRange\": [229, 230],\n          \"type\": \"Time\",\n          \"time\": \"220s\"\n        },\n        {\n          \"dmxRange\": [231, 233],\n          \"type\": \"Time\",\n          \"time\": \"230s\"\n        },\n        {\n          \"dmxRange\": [234, 235],\n          \"type\": \"Time\",\n          \"time\": \"240s\"\n        },\n        {\n          \"dmxRange\": [236, 238],\n          \"type\": \"Time\",\n          \"time\": \"250s\"\n        },\n        {\n          \"dmxRange\": [239, 240],\n          \"type\": \"Time\",\n          \"time\": \"260s\"\n        },\n        {\n          \"dmxRange\": [241, 243],\n          \"type\": \"Time\",\n          \"time\": \"270s\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"Time\",\n          \"time\": \"280s\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Time\",\n          \"time\": \"290s\"\n        },\n        {\n          \"dmxRange\": [249, 250],\n          \"type\": \"Time\",\n          \"time\": \"300s\"\n        },\n        {\n          \"dmxRange\": [251, 254],\n          \"type\": \"Time\",\n          \"time\": \"310s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow cue Data\"\n        }\n      ]\n    },\n    \"Gobo Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Time\",\n          \"time\": \"0s\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Time\",\n          \"time\": \"0.2s\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Time\",\n          \"time\": \"0.4s\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Time\",\n          \"time\": \"0.6s\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Time\",\n          \"time\": \"0.8s\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Time\",\n          \"time\": \"1s\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Time\",\n          \"time\": \"1.2s\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Time\",\n          \"time\": \"1.4s\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Time\",\n          \"time\": \"1.6s\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Time\",\n          \"time\": \"1.8s\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Time\",\n          \"time\": \"2s\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Time\",\n          \"time\": \"2.2s\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Time\",\n          \"time\": \"2.4s\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Time\",\n          \"time\": \"2.6s\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Time\",\n          \"time\": \"2.8s\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Time\",\n          \"time\": \"3s\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Time\",\n          \"time\": \"3.2s\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Time\",\n          \"time\": \"3.4s\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Time\",\n          \"time\": \"3.6s\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Time\",\n          \"time\": \"3.8s\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Time\",\n          \"time\": \"4s\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Time\",\n          \"time\": \"4.2s\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Time\",\n          \"time\": \"4.4s\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Time\",\n          \"time\": \"4.6s\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Time\",\n          \"time\": \"4.8s\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Time\",\n          \"time\": \"5s\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Time\",\n          \"time\": \"5.2s\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Time\",\n          \"time\": \"5.4s\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Time\",\n          \"time\": \"5.6s\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Time\",\n          \"time\": \"5.8s\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Time\",\n          \"time\": \"6s\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Time\",\n          \"time\": \"6.2s\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Time\",\n          \"time\": \"6.4s\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Time\",\n          \"time\": \"6.6s\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Time\",\n          \"time\": \"6.8s\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Time\",\n          \"time\": \"7s\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Time\",\n          \"time\": \"7.2s\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Time\",\n          \"time\": \"7.4s\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Time\",\n          \"time\": \"7.6s\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Time\",\n          \"time\": \"7.8s\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Time\",\n          \"time\": \"8s\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Time\",\n          \"time\": \"8.2s\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Time\",\n          \"time\": \"8.4s\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"Time\",\n          \"time\": \"8.6s\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Time\",\n          \"time\": \"8.8s\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Time\",\n          \"time\": \"9s\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Time\",\n          \"time\": \"9.2s\"\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Time\",\n          \"time\": \"9.4s\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Time\",\n          \"time\": \"9.6s\"\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Time\",\n          \"time\": \"9.8s\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Time\",\n          \"time\": \"10s\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Time\",\n          \"time\": \"10.2s\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Time\",\n          \"time\": \"10.4s\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Time\",\n          \"time\": \"10.6s\"\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"Time\",\n          \"time\": \"11s\"\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"Time\",\n          \"time\": \"12s\"\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"Time\",\n          \"time\": \"13s\"\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"Time\",\n          \"time\": \"14s\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"Time\",\n          \"time\": \"15s\"\n        },\n        {\n          \"dmxRange\": [65, 67],\n          \"type\": \"Time\",\n          \"time\": \"16s\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"Time\",\n          \"time\": \"17s\"\n        },\n        {\n          \"dmxRange\": [70, 72],\n          \"type\": \"Time\",\n          \"time\": \"18s\"\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"Time\",\n          \"time\": \"19s\"\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"Time\",\n          \"time\": \"20s\"\n        },\n        {\n          \"dmxRange\": [78, 80],\n          \"type\": \"Time\",\n          \"time\": \"21s\"\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"Time\",\n          \"time\": \"22s\"\n        },\n        {\n          \"dmxRange\": [83, 85],\n          \"type\": \"Time\",\n          \"time\": \"23s\"\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"Time\",\n          \"time\": \"24s\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Time\",\n          \"time\": \"25s\"\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"Time\",\n          \"time\": \"26s\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Time\",\n          \"time\": \"27s\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"Time\",\n          \"time\": \"28s\"\n        },\n        {\n          \"dmxRange\": [98, 100],\n          \"type\": \"Time\",\n          \"time\": \"29s\"\n        },\n        {\n          \"dmxRange\": [101, 103],\n          \"type\": \"Time\",\n          \"time\": \"30s\"\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"Time\",\n          \"time\": \"31s\"\n        },\n        {\n          \"dmxRange\": [106, 108],\n          \"type\": \"Time\",\n          \"time\": \"32s\"\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"Time\",\n          \"time\": \"33s\"\n        },\n        {\n          \"dmxRange\": [111, 113],\n          \"type\": \"Time\",\n          \"time\": \"34s\"\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"Time\",\n          \"time\": \"35s\"\n        },\n        {\n          \"dmxRange\": [116, 118],\n          \"type\": \"Time\",\n          \"time\": \"36s\"\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"Time\",\n          \"time\": \"37s\"\n        },\n        {\n          \"dmxRange\": [121, 123],\n          \"type\": \"Time\",\n          \"time\": \"38s\"\n        },\n        {\n          \"dmxRange\": [124, 126],\n          \"type\": \"Time\",\n          \"time\": \"39s\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"Time\",\n          \"time\": \"40s\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Time\",\n          \"time\": \"41s\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"Time\",\n          \"time\": \"42s\"\n        },\n        {\n          \"dmxRange\": [134, 136],\n          \"type\": \"Time\",\n          \"time\": \"43s\"\n        },\n        {\n          \"dmxRange\": [137, 138],\n          \"type\": \"Time\",\n          \"time\": \"44s\"\n        },\n        {\n          \"dmxRange\": [139, 141],\n          \"type\": \"Time\",\n          \"time\": \"45s\"\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"Time\",\n          \"time\": \"46s\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"Time\",\n          \"time\": \"47s\"\n        },\n        {\n          \"dmxRange\": [147, 148],\n          \"type\": \"Time\",\n          \"time\": \"48s\"\n        },\n        {\n          \"dmxRange\": [149, 151],\n          \"type\": \"Time\",\n          \"time\": \"49s\"\n        },\n        {\n          \"dmxRange\": [152, 154],\n          \"type\": \"Time\",\n          \"time\": \"50s\"\n        },\n        {\n          \"dmxRange\": [155, 156],\n          \"type\": \"Time\",\n          \"time\": \"51s\"\n        },\n        {\n          \"dmxRange\": [157, 159],\n          \"type\": \"Time\",\n          \"time\": \"52s\"\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"Time\",\n          \"time\": \"53s\"\n        },\n        {\n          \"dmxRange\": [162, 164],\n          \"type\": \"Time\",\n          \"time\": \"54s\"\n        },\n        {\n          \"dmxRange\": [165, 166],\n          \"type\": \"Time\",\n          \"time\": \"55s\"\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"Time\",\n          \"time\": \"56s\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Time\",\n          \"time\": \"57s\"\n        },\n        {\n          \"dmxRange\": [172, 174],\n          \"type\": \"Time\",\n          \"time\": \"58s\"\n        },\n        {\n          \"dmxRange\": [175, 177],\n          \"type\": \"Time\",\n          \"time\": \"59s\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"Time\",\n          \"time\": \"60s\"\n        },\n        {\n          \"dmxRange\": [180, 182],\n          \"type\": \"Time\",\n          \"time\": \"65s\"\n        },\n        {\n          \"dmxRange\": [183, 184],\n          \"type\": \"Time\",\n          \"time\": \"70s\"\n        },\n        {\n          \"dmxRange\": [185, 187],\n          \"type\": \"Time\",\n          \"time\": \"75s\"\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"Time\",\n          \"time\": \"80s\"\n        },\n        {\n          \"dmxRange\": [190, 192],\n          \"type\": \"Time\",\n          \"time\": \"85s\"\n        },\n        {\n          \"dmxRange\": [193, 194],\n          \"type\": \"Time\",\n          \"time\": \"90s\"\n        },\n        {\n          \"dmxRange\": [195, 197],\n          \"type\": \"Time\",\n          \"time\": \"95s\"\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"Time\",\n          \"time\": \"100s\"\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"Time\",\n          \"time\": \"110s\"\n        },\n        {\n          \"dmxRange\": [203, 205],\n          \"type\": \"Time\",\n          \"time\": \"120s\"\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"Time\",\n          \"time\": \"130s\"\n        },\n        {\n          \"dmxRange\": [208, 210],\n          \"type\": \"Time\",\n          \"time\": \"140s\"\n        },\n        {\n          \"dmxRange\": [211, 212],\n          \"type\": \"Time\",\n          \"time\": \"150s\"\n        },\n        {\n          \"dmxRange\": [213, 215],\n          \"type\": \"Time\",\n          \"time\": \"160s\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"Time\",\n          \"time\": \"170s\"\n        },\n        {\n          \"dmxRange\": [218, 220],\n          \"type\": \"Time\",\n          \"time\": \"180s\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"Time\",\n          \"time\": \"190s\"\n        },\n        {\n          \"dmxRange\": [223, 225],\n          \"type\": \"Time\",\n          \"time\": \"200s\"\n        },\n        {\n          \"dmxRange\": [226, 228],\n          \"type\": \"Time\",\n          \"time\": \"210s\"\n        },\n        {\n          \"dmxRange\": [229, 230],\n          \"type\": \"Time\",\n          \"time\": \"220s\"\n        },\n        {\n          \"dmxRange\": [231, 233],\n          \"type\": \"Time\",\n          \"time\": \"230s\"\n        },\n        {\n          \"dmxRange\": [234, 235],\n          \"type\": \"Time\",\n          \"time\": \"240s\"\n        },\n        {\n          \"dmxRange\": [236, 238],\n          \"type\": \"Time\",\n          \"time\": \"250s\"\n        },\n        {\n          \"dmxRange\": [239, 240],\n          \"type\": \"Time\",\n          \"time\": \"260s\"\n        },\n        {\n          \"dmxRange\": [241, 243],\n          \"type\": \"Time\",\n          \"time\": \"270s\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"Time\",\n          \"time\": \"280s\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Time\",\n          \"time\": \"290s\"\n        },\n        {\n          \"dmxRange\": [249, 250],\n          \"type\": \"Time\",\n          \"time\": \"300s\"\n        },\n        {\n          \"dmxRange\": [251, 254],\n          \"type\": \"Time\",\n          \"time\": \"310s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow cue Data\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard 32-channel\",\n      \"shortName\": \"32ch\",\n      \"channels\": [\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Iris\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Animation Disk\",\n        \"Animation Disk Rotation\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Zoom\",\n        \"Autofocus Distance\",\n        \"Autofocus Adjust\",\n        \"Effects\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Function\",\n        \"Reset\",\n        \"Lamp Control\"\n      ]\n    },\n    {\n      \"name\": \"Vector 36-channel\",\n      \"shortName\": \"36ch\",\n      \"channels\": [\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Iris\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Animation Disk\",\n        \"Animation Disk Rotation\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Zoom\",\n        \"Autofocus Distance\",\n        \"Autofocus Adjust\",\n        \"Effects\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Function\",\n        \"Reset\",\n        \"Lamp Control\",\n        \"Pan/Tilt Time\",\n        \"Color Time\",\n        \"Beam Time\",\n        \"Gobo Time\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/clay-paky/sharpy.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Sharpy\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Massimo Callegari\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-01-30\",\n    \"lastModifyDate\": \"2018-09-04\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-01-30\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.7.5 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://e-assist.tech/servlet/checkDocumentsFile?Id=284\"\n    ],\n    \"productPage\": [\n      \"https://www.claypaky.it/products/sharpy/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wcwxPytxm10\",\n      \"https://www.youtube.com/watch?v=XNa2c79-Wgw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [405, 450, 330],\n    \"weight\": 19,\n    \"power\": 200,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"MSD 200W\",\n      \"colorTemperature\": 8000,\n      \"lumens\": 7950\n    },\n    \"lens\": {\n      \"name\": \"Other\",\n      \"degreesMinMax\": [0, 3.8]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#c41c1a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ed8229\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aquamarine\",\n          \"colors\": [\"#7abd82\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#05822b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#9ec233\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#8f73ad\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ed8080\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffed00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#e30082\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00a6eb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO 260\",\n          \"colors\": [\"#f5c745\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO 190\",\n          \"colors\": [\"#f5d985\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB 8000\",\n          \"colors\": [\"#96c7b8\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#004f99\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [13, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [18, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [26, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [35, 38],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [39, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [43, 46],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [47, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 68],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [77, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [82, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [86, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [90, 93],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [94, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [99, 102],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [103, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [107, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 13,\n          \"slotNumberEnd\": 14\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 14,\n          \"slotNumberEnd\": 15\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 15,\n          \"slotNumberEnd\": 16\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"0.2rpm\",\n          \"speedEnd\": \"160rpm\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"12Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"30bpm\",\n          \"speedEnd\": \"360bpm\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 225],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [226, 238],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"50%\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [239, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [72, 113],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"-60rpm\",\n          \"speedEnd\": \"-5rpm\"\n        },\n        {\n          \"dmxRange\": [114, 117],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [118, 159],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"5rpm\",\n          \"speedEnd\": \"60rpm\"\n        },\n        {\n          \"dmxRange\": [160, 166],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [167, 172],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [173, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [180, 185],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [186, 191],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [192, 198],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [199, 204],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [205, 211],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [212, 217],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [218, 223],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [224, 230],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [231, 236],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [237, 243],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 16,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 17,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        }\n      ]\n    },\n    \"Prism Insertion\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [21, 41],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"90deg\"\n        },\n        {\n          \"dmxRange\": [42, 62],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"180deg\"\n        },\n        {\n          \"dmxRange\": [63, 83],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"270deg\"\n        },\n        {\n          \"dmxRange\": [84, 104],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [105, 126],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"450deg\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"-43rpm\",\n          \"speedEnd\": \"-0.183rpm\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"0.183rpm\",\n          \"speedEnd\": \"43rpm\"\n        }\n      ]\n    },\n    \"Effects Movement\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"Frost\": {\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"250deg\"\n      }\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan-Tilt Function (Fast - Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [25, 37],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan-Tilt Function (Normal)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [38, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve Function (Conventional)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [51, 62],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve Function (Linear - Default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [63, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 76],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Effects Reset\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [77, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt Reset\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Complete Reset\",\n          \"hold\": \"5s\"\n        }\n      ]\n    },\n    \"Lamp Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\",\n          \"hold\": \"5s\"\n        }\n      ]\n    },\n    \"Pan/Tilt Time\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"durationStart\": \"0s\",\n        \"durationEnd\": \"310s\"\n      }\n    },\n    \"Color Wheel Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"0s\",\n        \"timeEnd\": \"310s\"\n      }\n    },\n    \"Beam Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"0s\",\n        \"timeEnd\": \"310s\",\n        \"comment\": \"Dimmer, Frost, Prism\"\n      }\n    },\n    \"Gobo Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"0s\",\n        \"timeEnd\": \"310s\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"channels\": [\n        \"Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Gobo Wheel\",\n        \"Prism Insertion\",\n        \"Prism Rotation\",\n        \"Effects Movement\",\n        \"Frost\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Function\",\n        \"Reset\",\n        \"Lamp Control\"\n      ]\n    },\n    {\n      \"name\": \"Vector\",\n      \"channels\": [\n        \"Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Gobo Wheel\",\n        \"Prism Insertion\",\n        \"Prism Rotation\",\n        \"Effects Movement\",\n        \"Frost\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Function\",\n        \"Reset\",\n        \"Lamp Control\",\n        \"Pan/Tilt Time\",\n        \"Color Wheel Time\",\n        \"Beam Time\",\n        \"Gobo Time\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/clay-paky/show-batten-100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Show-Batten 100\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-05-16\",\n    \"lastModifyDate\": \"2018-08-09\",\n    \"importPlugin\": {\n      \"plugin\": \"gdtf\",\n      \"date\": \"2018-09-17\",\n      \"comment\": \"GDTF fixture type ID: 00 1B 21 63 BA 95 00 00 8F 2D C1 C7 D0 41 38 46\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.claypaky.it/media/documents/HR_ShowBatten100_Manual_05.2016_EN.pdf\",\n      \"https://www.claypaky.it/media/documents/ShowBatten100_DMX-Channels_05.2016.pdf\",\n      \"https://www.claypaky.it/media/documents/ShowBatten100_User-Menu_05.2016_EN.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.claypaky.it/en/products/showbatten100\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2n3CmtSITH0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1000, 100, 186],\n    \"weight\": 10,\n    \"power\": 170,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"10x 15W RGBW LED (Osram Ostar SMT LE RTDUW S2W)\",\n      \"colorTemperature\": 6000,\n      \"lumens\": 6800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 43]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [10, 1, 1]\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"CTO\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Does this capability already end at 8?\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"8000K\",\n          \"colorTemperatureEnd\": \"2500K\"\n        }\n      ]\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e4000a\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00e400\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000e4\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00e4e4\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e8d100\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e403e4\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7fe4e4\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"7000K\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e4dabe\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"3700K\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cae4e4\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Black\"\n        },\n        {\n          \"dmxRange\": [20, 22],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e0dc00\"],\n          \"comment\": \"Medium Yellow\"\n        },\n        {\n          \"dmxRange\": [23, 26],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e7c08b\"],\n          \"comment\": \"Straw Tint\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#9b654d\"],\n          \"comment\": \"Surprise Peach\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e50009\"],\n          \"comment\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f99119\"],\n          \"comment\": \"Medium Amber\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e46300\"],\n          \"comment\": \"Gold Amber\"\n        },\n        {\n          \"dmxRange\": [32, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ee1a00\"],\n          \"comment\": \"Dark Amber\"\n        },\n        {\n          \"dmxRange\": [35, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#db5431\"],\n          \"comment\": \"Sunrise Red\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e0a9cb\"],\n          \"comment\": \"Light Pink\"\n        },\n        {\n          \"dmxRange\": [46, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e086b9\"],\n          \"comment\": \"Medium Pink\"\n        },\n        {\n          \"dmxRange\": [49, 61],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d360cc\"],\n          \"comment\": \"Pink Carnation\"\n        },\n        {\n          \"dmxRange\": [62, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#9583ce\"],\n          \"comment\": \"Light Lavender\"\n        },\n        {\n          \"dmxRange\": [68, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6c1cbe\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [78, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0060cd\"],\n          \"comment\": \"Sky Blue\"\n        },\n        {\n          \"dmxRange\": [89, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#002cbd\"],\n          \"comment\": \"Just Blue\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#006d21\"],\n          \"comment\": \"Dark Yellow Green\"\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d6dc2d\"],\n          \"comment\": \"Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f1c45b\"],\n          \"comment\": \"Light Amber\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d7d1b9\"],\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f7af00\"],\n          \"comment\": \"Deep Amber\"\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ef7f00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f980a9\"],\n          \"comment\": \"Light Rose\"\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#eda18e\"],\n          \"comment\": \"English Rose\"\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f892b1\"],\n          \"comment\": \"Light Salmon\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e984c9\"],\n          \"comment\": \"Middle Rose\"\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ec47b6\"],\n          \"comment\": \"Dark Pink\"\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c3005a\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00afbe\"],\n          \"comment\": \"Peacock Blue\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#008192\"],\n          \"comment\": \"Med Blue Green\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#53bddf\"],\n          \"comment\": \"Steel Blue\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#003987\"],\n          \"comment\": \"Light Blue\"\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000a8\"],\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [131, 133],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#53d655\"],\n          \"comment\": \"Leaf Green\"\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00aa55\"],\n          \"comment\": \"Dark Green\"\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7e008f\"],\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [138, 141],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cc009e\"],\n          \"comment\": \"Bright Pink\"\n        },\n        {\n          \"dmxRange\": [142, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#004eb6\"],\n          \"comment\": \"Medium Blue\"\n        },\n        {\n          \"dmxRange\": [145, 145],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e30000\"],\n          \"comment\": \"Deep Golden Amber\"\n        },\n        {\n          \"dmxRange\": [146, 146],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#af95cb\"],\n          \"comment\": \"Pale Lavender\"\n        },\n        {\n          \"dmxRange\": [147, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8472db\"],\n          \"comment\": \"Special Lavender\"\n        },\n        {\n          \"dmxRange\": [149, 150],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#007100\"],\n          \"comment\": \"Primary Green\"\n        },\n        {\n          \"dmxRange\": [151, 156],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#007ad1\"],\n          \"comment\": \"Bright Blue\"\n        },\n        {\n          \"dmxRange\": [157, 161],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#eb9b6f\"],\n          \"comment\": \"Apricot\"\n        },\n        {\n          \"dmxRange\": [162, 167],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2b6b4\"],\n          \"comment\": \"Pale Gold\"\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#df6300\"],\n          \"comment\": \"Deep Orange\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#edc3c4\"],\n          \"comment\": \"Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e2001f\"],\n          \"comment\": \"Flame Red\"\n        },\n        {\n          \"dmxRange\": [175, 177],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0077d8\"],\n          \"comment\": \"Daylight Blue\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#beb1d6\"],\n          \"comment\": \"Lilac Tint\"\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#996ebb\"],\n          \"comment\": \"Deep Lavender\"\n        },\n        {\n          \"dmxRange\": [184, 190],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4c8bd7\"],\n          \"comment\": \"Dark Steel Blue\"\n        },\n        {\n          \"dmxRange\": [191, 206],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Congo Blue\"\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#004fbf\"],\n          \"comment\": \"Alice Blue\"\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbad6a\"],\n          \"comment\": \"Dirty White\"\n        },\n        {\n          \"dmxRange\": [209, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [4, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"24Hz\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [75, 140],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"24Hz\",\n          \"helpWanted\": \"Maybe 'Pulse' instead of 'Ramp up'?\"\n        },\n        {\n          \"dmxRange\": [141, 206],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"24Hz\",\n          \"speedEnd\": \"0.5Hz\",\n          \"helpWanted\": \"Maybe 'Pulse' instead of 'Ramp down'?\"\n        },\n        {\n          \"dmxRange\": [207, 211],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [212, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"1Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [225, 237],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"12.5Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [238, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"24Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"10deg\",\n        \"angleEnd\": \"43deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"240deg\"\n      }\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 102],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [103, 105],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Enable Pixel Mapping\"\n        },\n        {\n          \"dmxRange\": [106, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Free\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 76],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Zoom Reset\"\n        },\n        {\n          \"dmxRange\": [77, 127],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Tilt Reset\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Tilt and Zoom Reset\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic Engine\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macro\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Function\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"Pixel Engine RGB\",\n      \"shortName\": \"48ch\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macro\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Function\",\n        \"Reset\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Pixel Engine RGBW\",\n      \"shortName\": \"58ch\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTO\",\n        \"Color Macro\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Function\",\n        \"Reset\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/clay-paky/spheriscan.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Spheriscan\",\n  \"shortName\": \"CPSpheriscan\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-08-06\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.claypaky.it/media/documents/Spheriscan-Spherilight_Manual_04.2017_EN.pdf\",\n      \"https://www.claypaky.it/media/documents/Spheriscan_DMX-Channels_08.2016.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=d3FvqNGtDx8&t=320\",\n      \"https://www.youtube.com/watch?v=pHfReMDC78E\",\n      \"https://www.youtube.com/watch?v=ZUiQGT95se8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [497, 886, 282],\n    \"weight\": 31.5,\n    \"power\": 1600,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"OSRAM Lok-it 1400-PS L\",\n      \"colorTemperature\": 6000,\n      \"lumens\": 120000\n    },\n    \"lens\": {\n      \"name\": \"80mm\",\n      \"degreesMinMax\": [13, 34]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark red\",\n          \"colors\": [\"#dc2919\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Brilliant blue\",\n          \"colors\": [\"#234faa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#51bc49\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Half minus green\",\n          \"colors\": [\"#eee2d8\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light orange\",\n          \"colors\": [\"#ff9c35\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark orange\",\n          \"colors\": [\"#ff4f23\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Navy blue\",\n          \"colors\": [\"#1356a4\"]\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Small Dots\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Shuffle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Floating Squares\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Random Lines\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Large Bubbles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Shattered\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Big Dots\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Tunnel\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Clouds\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Eccentric Circle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Multiple Cones\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Fat Line\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Half Circle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Linear Dots\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"0.73rpm\",\n          \"speedEnd\": \"160rpm\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"12Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 225],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [226, 238],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"50%\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [239, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Iris\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"closed\",\n          \"openPercentEnd\": \"open\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [132, 171],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [172, 211],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [212, 251],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 113],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"60rpm\",\n          \"speedEnd\": \"5rpm\"\n        },\n        {\n          \"dmxRange\": [114, 117],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [118, 159],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"-5rpm\",\n          \"speedEnd\": \"-60rpm\"\n        },\n        {\n          \"dmxRange\": [160, 171],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [172, 183],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [184, 195],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [196, 207],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [208, 219],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [220, 231],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [232, 243],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        },\n        {\n          \"dmxRange\": [244, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"24bpm\",\n          \"shakeSpeedEnd\": \"600bpm\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [19, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [38, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [57, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [75, 92],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [93, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [112, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [130, 150],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 171],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [172, 192],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [193, 213],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [214, 234],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [235, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Gobo Stencil Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Stencil Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 125],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [126, 190],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"180rpm\",\n          \"speedEnd\": \"0.36rpm\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"-0.36rpm\",\n          \"speedEnd\": \"-180rpm\"\n        }\n      ]\n    },\n    \"Prism insertion\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"80rpm\",\n          \"speedEnd\": \"0.05rpm\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"-0.05rpm\",\n          \"speedEnd\": \"-80rpm\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"13deg\",\n        \"angleEnd\": \"34deg\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 24],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fast pan / tilt speed (default)\"\n        },\n        {\n          \"dmxRange\": [25, 37],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Normal pan / tilt speed\"\n        },\n        {\n          \"dmxRange\": [38, 50],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Conventional dimmer curve\"\n        },\n        {\n          \"dmxRange\": [51, 62],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Standard dimmer curve (default)\"\n        },\n        {\n          \"dmxRange\": [63, 139],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [140, 152],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fast gobo change (default)\"\n        },\n        {\n          \"dmxRange\": [153, 164],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Normal Gobo change\"\n        },\n        {\n          \"dmxRange\": [165, 177],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [178, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Mirror rotation inversion\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 76],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Zoom reset\"\n        },\n        {\n          \"dmxRange\": [77, 127],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan / tilt reset\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Complete reset\"\n        }\n      ]\n    },\n    \"Lamp control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 100],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Lamp off\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Lamp on\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"720deg\"\n      }\n    },\n    \"Pan Continuous\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 126],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"60deg\"\n      }\n    },\n    \"Strip LED Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Strip LED Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Strip LED Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Pan/Tilt Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"PanTiltSpeed\",\n          \"durationStart\": \"0s\",\n          \"durationEnd\": \"310s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow cue data\",\n          \"helpWanted\": \"What does this mean?\"\n        }\n      ]\n    },\n    \"Color Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"Time\",\n          \"timeStart\": \"0s\",\n          \"timeEnd\": \"310s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow cue data\",\n          \"helpWanted\": \"What does this mean?\"\n        }\n      ]\n    },\n    \"Beam Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"Time\",\n          \"timeStart\": \"0s\",\n          \"timeEnd\": \"310s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow cue data\",\n          \"helpWanted\": \"What does this mean?\"\n        }\n      ]\n    },\n    \"Gobo Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"Time\",\n          \"timeStart\": \"0s\",\n          \"timeEnd\": \"310s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow cue data\",\n          \"helpWanted\": \"What does this mean?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Iris\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Gobo Stencil Rotation fine\",\n        \"Prism insertion\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Zoom\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Function\",\n        \"Reset\",\n        \"Lamp control\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Pan Continuous\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Strip LED Red\",\n        \"Strip LED Green\",\n        \"Strip LED Blue\"\n      ]\n    },\n    {\n      \"name\": \"Vector\",\n      \"shortName\": \"vec\",\n      \"channels\": [\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Iris\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Gobo Stencil Rotation fine\",\n        \"Prism insertion\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Zoom\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Function\",\n        \"Reset\",\n        \"Lamp control\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Pan Continuous\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Strip LED Red\",\n        \"Strip LED Green\",\n        \"Strip LED Blue\",\n        \"Pan/Tilt Time\",\n        \"Color Time\",\n        \"Beam Time\",\n        \"Gobo Time\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/clf/hera.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hera\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Guigui\"],\n    \"createDate\": \"2019-08-21\",\n    \"lastModifyDate\": \"2019-08-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.clf-lighting.com/wp-content/uploads/CLF_HERA_Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.clf-lighting.com/product/hera\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=lxO2bXqmgJE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [260, 290, 180],\n    \"weight\": 3.8,\n    \"power\": 121,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"12× RGBWAUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [25, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Burst pulse\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"comment\": \"Burst pulse\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Sine wave\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [230, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"10000K\",\n        \"colorTemperatureEnd\": \"2500K\"\n      }\n    },\n    \"Color Wheel Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"helpWanted\": \"Do the colors fade or jump?\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 10 (cycle 1-10)\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 1\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 2\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 3\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 4\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 5\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 6\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 7\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 8\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 9\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom program 10\"\n        }\n      ]\n    },\n    \"Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Speed\",\n          \"comment\": \"Auto speed or dimmer speed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Fixture Control Settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 94],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Manual calibration output mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Raw color output mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal dimming, speed of changes unrestricted\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth dimming, speed of changes restricted slightly\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"Maintenance\",\n          \"comment\": \"1600 Hz refresh rate\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"11200 Hz refresh rate\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"12400 Hz refresh rate\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"14800 Hz refresh rate\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"WDMX on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"WDMX off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"WDMX reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [180, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Illuminate display\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Hue\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Saturation\"\n      }\n    },\n    \"Value\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Value\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"comment\": \"for HSI color mixing\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Color Temperature\",\n        \"Color Wheel Effect\",\n        \"Auto Programs\",\n        \"Speed\",\n        \"Fixture Control Settings\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Color Temperature\",\n        \"Color Wheel Effect\",\n        \"Auto Programs\",\n        \"Speed\",\n        \"Fixture Control Settings\"\n      ]\n    },\n    {\n      \"name\": \"HSV\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Value\"\n      ]\n    },\n    {\n      \"name\": \"HSI\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/coemar/prospot-250-lx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ProSpot 250 LX\",\n  \"shortName\": \"CoemarPSpotLX\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-09-11\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.coemar.com/wp-content/uploads/2018/02/Prospot_250_LX_E1.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=6Oa7vMm9c4Y\",\n      \"https://www.youtube.com/watch?v=QwHsxx6IGE8\",\n      \"https://www.youtube.com/watch?v=zOzbAp4v6wg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [350, 510, 377],\n    \"weight\": 23.5,\n    \"power\": 460,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"Philips MSD 250W/2\",\n      \"colorTemperature\": 8500,\n      \"lumens\": 18000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"530deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"284deg\"\n      }\n    },\n    \"Pan / Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"standard\"\n        },\n        {\n          \"dmxRange\": [11, 25],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"200%\",\n          \"comment\": \"for programming\"\n        },\n        {\n          \"dmxRange\": [26, 127],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Vector mode\"\n        },\n        {\n          \"dmxRange\": [128, 247],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Tracking mode\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Tracking mode\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"dark\",\n          \"brightnessEnd\": \"bright\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 66],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [67, 68],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [69, 125],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [185, 187],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [188, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\",\n        \"helpWanted\": \"Correct direction?\"\n      }\n    },\n    \"Gobo selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [111, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [128, 192],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo stencil rotation angle\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        }\n      ]\n    },\n    \"Gobo stencil rotation speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 131],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [132, 134],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [135, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\"\n        },\n        {\n          \"dmxRange\": [21, 136],\n          \"type\": \"Prism\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"comment\": \"3-facet\"\n        },\n        {\n          \"dmxRange\": [137, 139],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\",\n          \"comment\": \"3-facet\"\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"comment\": \"3-facet\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [60, 127],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo shake / Blackout effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 249],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blackout during movements\"\n        }\n      ]\n    },\n    \"Gobo shake amplitude\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 23],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"100%\"\n        },\n        {\n          \"dmxRange\": [24, 47],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"91%\"\n        },\n        {\n          \"dmxRange\": [48, 71],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"82%\"\n        },\n        {\n          \"dmxRange\": [72, 95],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"73%\"\n        },\n        {\n          \"dmxRange\": [96, 119],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"64%\"\n        },\n        {\n          \"dmxRange\": [120, 143],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"55%\"\n        },\n        {\n          \"dmxRange\": [144, 167],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"45%\"\n        },\n        {\n          \"dmxRange\": [168, 191],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"36%\"\n        },\n        {\n          \"dmxRange\": [192, 215],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"27%\"\n        },\n        {\n          \"dmxRange\": [216, 239],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"18%\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeAngle\": \"9%\"\n        }\n      ]\n    },\n    \"Lamp on / Motor reset\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\",\n          \"hold\": \"6s\"\n        },\n        {\n          \"dmxRange\": [20, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No effects (idle)\",\n          \"hold\": \"6s\"\n        },\n        {\n          \"dmxRange\": [101, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Effects reset (once), no Pan / Tilt movement\",\n          \"hold\": \"6s\"\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motor reset (once)\",\n          \"hold\": \"6s\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent fans (if external temperature allows it)\",\n          \"hold\": \"6s\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\",\n          \"hold\": \"6s\"\n        }\n      ]\n    },\n    \"Pan / Tilt Speed (Emulation mode)\": {\n      \"name\": \"Pan / Tilt Speed\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [1, 249],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Blackout during movements\"\n        }\n      ]\n    },\n    \"Lamp on / Fan speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan speed\",\n          \"parameterStart\": \"fast\",\n          \"parameterEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on, reset\"\n        },\n        {\n          \"dmxRange\": [140, 229],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Effect wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 95],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open / hole\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet rotating\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 1\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 2\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 3\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 4\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 5\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 6\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 7\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 8\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 9\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 10\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 11\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism / Gobo macro 12\"\n        }\n      ]\n    },\n    \"3 facet prism rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 126],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo selection (Emulation mode)\": {\n      \"name\": \"Gobo selection\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo stencil rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter / Strobe (Emulation mode)\": {\n      \"name\": \"Shutter / Strobe\",\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer (Emulation mode)\": {\n      \"name\": \"Dimmer\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"strd\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan / Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Focus\",\n        \"Gobo selection\",\n        \"Gobo stencil rotation angle\",\n        \"Gobo stencil rotation speed\",\n        \"Prism\",\n        \"Color Wheel\",\n        \"Gobo shake / Blackout effect\",\n        \"Gobo shake amplitude\",\n        \"Lamp on / Motor reset\"\n      ]\n    },\n    {\n      \"name\": \"ProSpot emulation\",\n      \"shortName\": \"emul\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan / Tilt Speed (Emulation mode)\",\n        \"Lamp on / Fan speed\",\n        \"Color Wheel\",\n        null,\n        \"Effect wheel\",\n        \"3 facet prism rotation\",\n        \"Gobo selection (Emulation mode)\",\n        \"Gobo stencil rotation\",\n        null,\n        \"Focus\",\n        \"Shutter / Strobe (Emulation mode)\",\n        \"Dimmer (Emulation mode)\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/contest/irled64-18x12six.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"irLED64 18x12SIX\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Edrig\", \"Ryan Goodwin\"],\n    \"createDate\": \"2023-04-24\",\n    \"lastModifyDate\": \"2023-04-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.contest-lighting.com/downloads/IrLED64-18x12SIX_manuel-V1-en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.contest-lighting.com/en/index.php?code=H10138&cat1=l10000&cat2=l24000&cat3=l12007&lang=en\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [340, 270, 220],\n    \"weight\": 5.4,\n    \"power\": 240,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 189],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [190, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Full power\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Off\",\n          \"colors\": [\"#000000\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff7f00\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff007f\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full White\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Apricot\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Ocre\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Pearl\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Grey Pearl\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Vernoese\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Lagon\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cerulean Blue\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fluo\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Candy\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra Violet\",\n          \"colors\": [\"#8800ff\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra Green\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra Blue\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra Pink\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra Light\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [226, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music-sensitive Macro 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music-sensitive Macro 7\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [242, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music-sensitive Macro 11\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music-sensitive Macro 14\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mic Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Program\",\n        \"Dimmer / Macro Speed / Mic Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer / Strobe\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer / Macro Speed / Mic Sensitivity\",\n        \"Strobe\",\n        \"Program\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/contest/irledflat-5x12SIXb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"IrLEDFLAT 5x12SIXb\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Pascal Denis\", \"Felix Edelmann\", \"JonahKr\"],\n    \"createDate\": \"2018-11-11\",\n    \"lastModifyDate\": \"2021-09-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.contest-lighting.com/downloads/IrLEDFLAT-5x12SIX_manuel-en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.contest-lighting.com/en/index.php?code=H10142&cat1=l10000&cat2=l24000&cat3=l12008\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [240, 265, 110],\n    \"weight\": 2.8,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"50Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 189],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [190, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"50Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ffaa00\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#faadf0\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"cold\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"warm\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#ffc8d2\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Apricot\",\n          \"colors\": [\"#fdd5b1\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Ocre\",\n          \"colors\": [\"#e1b150\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Pearl\",\n          \"colors\": [\"#134d24\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Grey Pearl\",\n          \"colors\": [\"#dee2d9\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Veronese\",\n          \"colors\": [\"#009b7d\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Lagon\",\n          \"colors\": [\"#03787c\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#46b4f0\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#00e1eb\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cerulean Blue\",\n          \"colors\": [\"#2a52be\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fluo\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Candy\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset\",\n          \"colors\": [\"#fad6a5\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra violet\",\n          \"colors\": [\"#3e0694\"],\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra Green\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra blue\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra Pink\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultra Light\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\",\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [226, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1 music-sensitive\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7 music-sensitive\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [242, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11 music-sensitive\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14 music-sensitive\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Dimmer / Macro Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mic Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\",\n        \"helpWanted\": \"Is it low…high or high…low?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Macros / Dimmer\",\n      \"shortName\": \"D2\",\n      \"channels\": [\n        \"Macros\",\n        \"Dimmer / Macro Speed / Mic Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"RGBD\",\n      \"shortName\": \"F4\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBDW\",\n      \"shortName\": \"G5\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer / Strobe\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"RGBWAUV\",\n      \"shortName\": \"A6\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"RGBWAUV / Dimmer and Strobe\",\n      \"shortName\": \"B7\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBWAUV / Dimmer / Strobe\",\n      \"shortName\": \"C8\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBWAUV / Dimmer / Strobe / Macros\",\n      \"shortName\": \"E9\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer / Macro Speed / Mic Sensitivity\",\n        \"Strobe\",\n        \"Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/dedolight/dled4-bi.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DLED4-BI\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Jean-François Losson\"],\n    \"createDate\": \"2018-11-11\",\n    \"lastModifyDate\": \"2018-11-11\"\n  },\n  \"comment\": \"The DT4-BI-DMX power supply is needed for DMX control.\",\n  \"links\": {\n    \"productPage\": [\n      \"https://www.dedoweigertfilm.de/dwf-en/products/dedolight/dedolight-dled-series4.php\"\n    ],\n    \"other\": [\n      \"https://www.mediatec.de/media/pdf/fa/f8/cb/DLED4_DATENBLATT_0005.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [109, 200, 100],\n    \"weight\": 1.3,\n    \"power\": 47,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"Bicolor 40W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"highlightValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6800K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"DT4-BI-DMX\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/dedolight/dled7-bi.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DLED7-BI\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"PY DOUGNAC\"],\n    \"createDate\": \"2018-12-19\",\n    \"lastModifyDate\": \"2018-12-19\"\n  },\n  \"comment\": \"The DT7-BI-DMX power supply is needed for DMX control.\",\n  \"links\": {\n    \"productPage\": [\n      \"https://www.dedoweigertfilm.de/dwf-en/products/dedolight/turbo-series.php\"\n    ],\n    \"other\": [\n      \"https://www.mediatec.de/media/pdf/04/d6/8c/TURBO_SERIE_BROSCHUERE_0005.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [109, 200, 100],\n    \"weight\": 1.3,\n    \"power\": 90,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"Bicolor 90W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2700K\",\n        \"colorTemperatureEnd\": \"6500K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"DT7-BI-DMX\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/desisti/softled-4-vw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SoftLED 4 VW\",\n  \"shortName\": \"SLED4VW\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Lukas Runge\", \"Luke Nelson\"],\n    \"createDate\": \"2023-10-15\",\n    \"lastModifyDate\": \"2023-10-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.desisti.it/soft-led-4/\"\n    ],\n    \"productPage\": [\n      \"https://www.desisti.it/wp-content/uploads/2018/10/CE-Instruction-Manual-De-Sisti-SOFT-LED-4VW.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [465, 480, 132],\n    \"weight\": 6.7,\n    \"power\": 205,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT Linear Mode\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2750K\",\n        \"colorTemperatureEnd\": \"6900K\"\n      }\n    },\n    \"CCT Step Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2750K\"\n        },\n        {\n          \"dmxRange\": [26, 51],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2880K\"\n        },\n        {\n          \"dmxRange\": [52, 77],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"dmxRange\": [78, 103],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [104, 129],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3500K\"\n        },\n        {\n          \"dmxRange\": [130, 155],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [156, 181],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4500K\"\n        },\n        {\n          \"dmxRange\": [182, 207],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [208, 233],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [234, 253],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6900K\"\n        }\n      ]\n    },\n    \"Color Temperature Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Mode\",\n          \"switchChannels\": {\n            \"CCT Linear Mode / CCT Step Mode\": \"CCT Linear Mode\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Step Mode\",\n          \"switchChannels\": {\n            \"CCT Linear Mode / CCT Step Mode\": \"CCT Step Mode\"\n          }\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"SLOT4\",\n      \"shortName\": \"S4\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT Linear Mode / CCT Step Mode\",\n        \"Color Temperature Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/desisti/softled-8-vw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SoftLED 8 VW\",\n  \"shortName\": \"SLED8VW\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Lukas Runge\", \"Luke Nelson\"],\n    \"createDate\": \"2023-10-15\",\n    \"lastModifyDate\": \"2023-10-15\"\n  },\n  \"comment\": \"Tunable White from 2800 to 6600 Kelvin\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.desisti.it/wp-content/uploads/2018/10/CE-Instruction-Manual-De-Sisti-SOFT-LED-8VW.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.desisti.it/soft-led-8/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [747, 480, 132],\n    \"weight\": 10,\n    \"power\": 450,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT Linear Mode\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2750K\",\n        \"colorTemperatureEnd\": \"6900K\"\n      }\n    },\n    \"CCT Step Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2750K\"\n        },\n        {\n          \"dmxRange\": [26, 51],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2880K\"\n        },\n        {\n          \"dmxRange\": [52, 77],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"dmxRange\": [78, 103],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [104, 129],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3500K\"\n        },\n        {\n          \"dmxRange\": [130, 155],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [156, 181],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4500K\"\n        },\n        {\n          \"dmxRange\": [182, 207],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [208, 233],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [234, 253],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6900K\"\n        }\n      ]\n    },\n    \"Color Temperature Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear Mode\",\n          \"switchChannels\": {\n            \"CCT Linear Mode / CCT Step Mode\": \"CCT Linear Mode\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Step Mode\",\n          \"switchChannels\": {\n            \"CCT Linear Mode / CCT Step Mode\": \"CCT Step Mode\"\n          }\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"SLOT4\",\n      \"shortName\": \"S4\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT Linear Mode / CCT Step Mode\",\n        \"Color Temperature Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/dmg-lumiere/maxi-mix.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAXI MIX\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-04-26\",\n    \"lastModifyDate\": \"2021-04-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://emea.rosco.com/sites/default/files/content/resource/2022-08/Rosco_DMG_User_ManualMAXIMIX2022.pdf\"\n    ],\n    \"productPage\": [\n      \"https://emea.rosco.com/en/product/dmg-maxi\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=sV_cSc4ulkA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1200, 360, 85],\n    \"weight\": 8,\n    \"power\": 360,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1700K\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1750K\"\n        },\n        {\n          \"dmxRange\": [13, 242],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1750K\",\n          \"colorTemperatureEnd\": \"9950K\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"9950K\"\n        },\n        {\n          \"dmxRange\": [244, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Green-Magenta Point\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [16, 114],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [115, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [141, 239],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"White Base Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Memory # Hundreds\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Memory # Tens\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Memory # Singles\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"name\": \"Hue\",\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9727],\n          \"type\": \"Generic\",\n          \"comment\": \"0°\"\n        },\n        {\n          \"dmxRange\": [9728, 55808],\n          \"type\": \"Generic\",\n          \"comment\": \"0-360°\"\n        },\n        {\n          \"dmxRange\": [55809, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"360°\"\n        }\n      ]\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 26],\n          \"type\": \"Generic\",\n          \"comment\": \"0%\"\n        },\n        {\n          \"dmxRange\": [27, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"1-99%\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"100%\"\n        }\n      ]\n    },\n    \"Hue Gel\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"-10…10\"\n      }\n    },\n    \"Saturation Gel\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"-20…20\"\n      }\n    },\n    \"Colorspace X Position\": {\n      \"fineChannelAliases\": [\"Colorspace X Position fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0.0…0.8\"\n      }\n    },\n    \"Colorspace Y Position\": {\n      \"fineChannelAliases\": [\"Colorspace Y Position fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0.0…0.8\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve linear\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve square\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve s curve\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve Tungsten\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CRMX unlink\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bluetooth on\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bluetooth off\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RDM off\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RDM on\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Slew Off\"\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Slew Set\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Save in myMIX\"\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Effects Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Cross Fade to Color\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"CCT … Color Mix\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [17, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"17.8Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: White 8-bit\",\n      \"shortName\": \"White\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"2: Color 8-bit\",\n      \"shortName\": \"Color\",\n      \"channels\": [\n        \"Dimmer\",\n        \"White Base Color\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"3: Gel 8-bit\",\n      \"shortName\": \"Gel\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\"\n      ]\n    },\n    {\n      \"name\": \"4: Pro 8-bit\",\n      \"shortName\": \"Pro8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Hue\",\n        \"Saturation\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\",\n        \"Effects Speed\",\n        \"Colorspace X Position\",\n        \"Colorspace Y Position\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"5: Pro 16-bit\",\n      \"shortName\": \"Pro16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\",\n        \"Effects Speed\",\n        \"Colorspace X Position\",\n        \"Colorspace X Position fine\",\n        \"Colorspace Y Position\",\n        \"Colorspace Y Position fine\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"6: Full 8-bit\",\n      \"shortName\": \"Full8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Lime\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"7: Full 16-bit\",\n      \"shortName\": \"Full16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Lime\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/dmg-lumiere/mini-mix.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MINI MIX\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-04-26\",\n    \"lastModifyDate\": \"2021-04-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://emea.rosco.com/sites/default/files/content/resource/2019-06/DMG%20MINI%20and%20SL1%20MIX%20User%20Guide.pdf\"\n    ],\n    \"productPage\": [\n      \"https://emea.rosco.com/en/product/dmg-mini\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=yE1hPXHohJM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [585, 205, 37],\n    \"weight\": 2.56,\n    \"power\": 100,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1700K\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1750K\"\n        },\n        {\n          \"dmxRange\": [13, 242],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1750K\",\n          \"colorTemperatureEnd\": \"9950K\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"9950K\"\n        },\n        {\n          \"dmxRange\": [244, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Green-Magenta Point\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [16, 114],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [115, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [141, 239],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"White Base Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Memory # Hundreds\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Memory # Tens\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Memory # Singles\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"name\": \"Hue\",\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9727],\n          \"type\": \"Generic\",\n          \"comment\": \"0°\"\n        },\n        {\n          \"dmxRange\": [9728, 55808],\n          \"type\": \"Generic\",\n          \"comment\": \"0-360°\"\n        },\n        {\n          \"dmxRange\": [55809, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"360°\"\n        }\n      ]\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 26],\n          \"type\": \"Generic\",\n          \"comment\": \"0%\"\n        },\n        {\n          \"dmxRange\": [27, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"1-99%\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"100%\"\n        }\n      ]\n    },\n    \"Hue Gel\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"-10…10\"\n      }\n    },\n    \"Saturation Gel\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"-20…20\"\n      }\n    },\n    \"Colorspace X Position\": {\n      \"fineChannelAliases\": [\"Colorspace X Position fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0.0…0.8\"\n      }\n    },\n    \"Colorspace Y Position\": {\n      \"fineChannelAliases\": [\"Colorspace Y Position fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0.0…0.8\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve linear\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve square\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve s curve\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve Tungsten\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CRMX unlink\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bluetooth on\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bluetooth off\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RDM off\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RDM on\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Slew Off\"\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Slew Set\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Save in myMIX\"\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Effects Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Cross Fade to Color\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"CCT … Color Mix\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [17, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"17.8Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: White 8-bit\",\n      \"shortName\": \"White\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"2: Color 8-bit\",\n      \"shortName\": \"Color\",\n      \"channels\": [\n        \"Dimmer\",\n        \"White Base Color\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"3: Gel 8-bit\",\n      \"shortName\": \"Gel\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\"\n      ]\n    },\n    {\n      \"name\": \"4: Pro 8-bit\",\n      \"shortName\": \"Pro8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Hue\",\n        \"Saturation\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\",\n        \"Effects Speed\",\n        \"Colorspace X Position\",\n        \"Colorspace Y Position\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"5: Pro 16-bit\",\n      \"shortName\": \"Pro16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\",\n        \"Effects Speed\",\n        \"Colorspace X Position\",\n        \"Colorspace X Position fine\",\n        \"Colorspace Y Position\",\n        \"Colorspace Y Position fine\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"6: Full 8-bit\",\n      \"shortName\": \"Full8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Lime\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"7: Full 16-bit\",\n      \"shortName\": \"Full16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Lime\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/dmg-lumiere/sl1-mix.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SL1 MIX\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-04-26\",\n    \"lastModifyDate\": \"2021-04-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://emea.rosco.com/sites/default/files/content/resource/2019-06/DMG%20MINI%20and%20SL1%20MIX%20User%20Guide.pdf\"\n    ],\n    \"productPage\": [\n      \"https://emea.rosco.com/en/product/dmg-sl1\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_EE9-9-C4Yk&t=200s\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1118, 205, 37],\n    \"weight\": 4.18,\n    \"power\": 200,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1700K\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1750K\"\n        },\n        {\n          \"dmxRange\": [13, 242],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1750K\",\n          \"colorTemperatureEnd\": \"9950K\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"9950K\"\n        },\n        {\n          \"dmxRange\": [244, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Green-Magenta Point\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [16, 114],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [115, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [141, 239],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"White Base Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Memory # Hundreds\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Memory # Tens\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Memory # Singles\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"0\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Generic\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Generic\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Generic\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"9\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"name\": \"Hue\",\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9727],\n          \"type\": \"Generic\",\n          \"comment\": \"0°\"\n        },\n        {\n          \"dmxRange\": [9728, 55808],\n          \"type\": \"Generic\",\n          \"comment\": \"0-360°\"\n        },\n        {\n          \"dmxRange\": [55809, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"360°\"\n        }\n      ]\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 26],\n          \"type\": \"Generic\",\n          \"comment\": \"0%\"\n        },\n        {\n          \"dmxRange\": [27, 224],\n          \"type\": \"Generic\",\n          \"comment\": \"1-99%\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"100%\"\n        }\n      ]\n    },\n    \"Hue Gel\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"-10…10\"\n      }\n    },\n    \"Saturation Gel\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"-20…20\"\n      }\n    },\n    \"Colorspace X Position\": {\n      \"fineChannelAliases\": [\"Colorspace X Position fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0.0…0.8\"\n      }\n    },\n    \"Colorspace Y Position\": {\n      \"fineChannelAliases\": [\"Colorspace Y Position fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0.0…0.8\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve linear\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve square\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve s curve\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve Tungsten\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CRMX unlink\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bluetooth on\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bluetooth off\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RDM off\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RDM on\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Slew Off\"\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Slew Set\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Save in myMIX\"\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Effects Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Cross Fade to Color\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"CCT … Color Mix\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [17, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"17.8Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: White 8-bit\",\n      \"shortName\": \"White\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"2: Color 8-bit\",\n      \"shortName\": \"Color\",\n      \"channels\": [\n        \"Dimmer\",\n        \"White Base Color\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"3: Gel 8-bit\",\n      \"shortName\": \"Gel\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\"\n      ]\n    },\n    {\n      \"name\": \"4: Pro 8-bit\",\n      \"shortName\": \"Pro8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Hue\",\n        \"Saturation\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\",\n        \"Effects Speed\",\n        \"Colorspace X Position\",\n        \"Colorspace Y Position\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"5: Pro 16-bit\",\n      \"shortName\": \"Pro16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Memory # Hundreds\",\n        \"Memory # Tens\",\n        \"Memory # Singles\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"White Base Color\",\n        \"Hue Gel\",\n        \"Saturation Gel\",\n        \"Effects Speed\",\n        \"Colorspace X Position\",\n        \"Colorspace X Position fine\",\n        \"Colorspace Y Position\",\n        \"Colorspace Y Position fine\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"6: Full 8-bit\",\n      \"shortName\": \"Full8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Lime\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"7: Full 16-bit\",\n      \"shortName\": \"Full16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Cross Fade to Color\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Lime\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/dts/scena-led-150.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Scena LED 150\",\n  \"shortName\": \"DTSScenaLED150\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Karl Humbug\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-07-01\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"comment\": \"Also available with 4000K or 5000K color temperature LED.\",\n  \"links\": {\n    \"manual\": [\n      \"https://dts-lighting.it/download/scena-led-150-m-pc/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Vvi90cLiRmo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 185, 330],\n    \"weight\": 5.3,\n    \"power\": 160,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"150W LED\",\n      \"colorTemperature\": 3000,\n      \"lumens\": 7000\n    },\n    \"lens\": {\n      \"name\": \"PC\",\n      \"degreesMinMax\": [8.2, 70]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [30, 119],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"33.3Hz\"\n        },\n        {\n          \"dmxRange\": [120, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"0.02Hz\",\n          \"speedEnd\": \"8.3Hz\"\n        },\n        {\n          \"dmxRange\": [150, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"0.02Hz\",\n          \"speedEnd\": \"8.3Hz\"\n        },\n        {\n          \"dmxRange\": [180, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"comment\": \"dimmer active\"\n        },\n        {\n          \"dmxRange\": [205, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"comment\": \"dimmer inactive\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Zoom Fresnel\": {\n      \"name\": \"Zoom\",\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"12.8deg\",\n        \"angleEnd\": \"62deg\",\n        \"comment\": \"linear\"\n      }\n    },\n    \"Zoom PC\": {\n      \"name\": \"Zoom\",\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"8.2deg\",\n        \"angleEnd\": \"70deg\",\n        \"comment\": \"linear\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Zoom Motor Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel (PC lens)\",\n      \"shortName\": \"5ch-pc\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom PC\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"4-channel (PC lens)\",\n      \"shortName\": \"4ch-pc\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Zoom PC\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"2-channel (PC lens)\",\n      \"shortName\": \"2ch-pc\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Zoom PC\"\n      ]\n    },\n    {\n      \"name\": \"5-channel (Fresnel lens)\",\n      \"shortName\": \"5ch-fres\",\n      \"physical\": {\n        \"weight\": 5.1,\n        \"lens\": {\n          \"name\": \"Fresnel\",\n          \"degreesMinMax\": [12.8, 62]\n        }\n      },\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom Fresnel\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"4-channel (Fresnel lens)\",\n      \"shortName\": \"4ch-fres\",\n      \"physical\": {\n        \"weight\": 5.1,\n        \"lens\": {\n          \"name\": \"Fresnel\",\n          \"degreesMinMax\": [12.8, 62]\n        }\n      },\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Zoom Fresnel\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"2-channel (Fresnel lens)\",\n      \"shortName\": \"2ch-fres\",\n      \"physical\": {\n        \"weight\": 5.1,\n        \"lens\": {\n          \"name\": \"Fresnel\",\n          \"degreesMinMax\": [12.8, 62]\n        }\n      },\n      \"channels\": [\n        \"Dimmer\",\n        \"Zoom Fresnel\"\n      ]\n    },\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/dts/xr1200-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"XR1200 WASH\",\n  \"shortName\": \"DTSXR1200\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-08-08\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://dts-lighting.it/download/xr1200-wash/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=uu0jVaHAUXU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [490, 685, 500],\n    \"weight\": 38,\n    \"power\": 1320,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Phililps MSR Gold 1200 Fastfit\",\n      \"lumens\": 50000\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#ffd85e\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB\",\n          \"colors\": [\"#d1ffff\"],\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#7038aa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00c628\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#f4001c\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#660adb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"320deg\"\n      }\n    },\n    \"Movement Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [11, 25],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [26, 127],\n          \"type\": \"PanTiltSpeed\",\n          \"comment\": \"Vector mode\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 247],\n          \"type\": \"PanTiltSpeed\",\n          \"comment\": \"Reaction time to DMX signal\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"comment\": \"Reaction time to DMX signal\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [9, 255],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"dark\",\n          \"brightnessEnd\": \"bright\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 23],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [24, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [108, 163],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Flash open\"\n        },\n        {\n          \"dmxRange\": [164, 219],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Flash closed\"\n        },\n        {\n          \"dmxRange\": [220, 227],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colors / Macros in black-out\"\n        },\n        {\n          \"dmxRange\": [228, 233],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan / Tilt in black-out\"\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [13, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [26, 38],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [39, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [52, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [65, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [78, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [91, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [104, 116],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [117, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [130, 142],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [143, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [156, 168],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [169, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [182, 197],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [198, 224],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [229, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Speed CMY / Dimmer\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Macro CMY / Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [115, 121],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 0\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [122, 128],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 2\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"20%\"\n        },\n        {\n          \"dmxRange\": [129, 135],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 3\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"30%\"\n        },\n        {\n          \"dmxRange\": [136, 142],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 4\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"40%\"\n        },\n        {\n          \"dmxRange\": [143, 149],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 5\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"50%\"\n        },\n        {\n          \"dmxRange\": [150, 156],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 6\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"60%\"\n        },\n        {\n          \"dmxRange\": [157, 163],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 7\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"70%\"\n        },\n        {\n          \"dmxRange\": [164, 170],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 8\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"80%\"\n        },\n        {\n          \"dmxRange\": [171, 177],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 9\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"90%\"\n        },\n        {\n          \"dmxRange\": [178, 184],\n          \"type\": \"Effect\",\n          \"comment\": \"Macros wait = 10\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"100%\"\n        },\n        {\n          \"dmxRange\": [185, 191],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 0\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [192, 198],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 2\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"20%\"\n        },\n        {\n          \"dmxRange\": [199, 205],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 3\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"30%\"\n        },\n        {\n          \"dmxRange\": [206, 212],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 4\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"40%\"\n        },\n        {\n          \"dmxRange\": [213, 219],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 5\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"50%\"\n        },\n        {\n          \"dmxRange\": [220, 226],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 6\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"60%\"\n        },\n        {\n          \"dmxRange\": [227, 233],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 7\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"70%\"\n        },\n        {\n          \"dmxRange\": [234, 240],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 8\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"80%\"\n        },\n        {\n          \"dmxRange\": [241, 247],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 9\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"90%\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"comment\": \"Full Colors wait = 10\",\n          \"effectPreset\": \"ColorFade\",\n          \"duration\": \"100%\"\n        }\n      ]\n    },\n    \"Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"100%\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"0%\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Beam shape\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\"\n      }\n    },\n    \"Lamp / Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp OFF\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [61, 129],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [130, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp ON\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [180, 200],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [201, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Internal Motors Reset\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Fresnel\",\n      \"physical\": {\n        \"lens\": {\n          \"name\": \"Fresnel Ø 200 mm\",\n          \"degreesMinMax\": [20, 45]\n        }\n      },\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Speed CMY / Dimmer\",\n        \"Macro CMY / Color\",\n        \"Effects\",\n        \"Zoom\",\n        \"Lamp / Reset\"\n      ]\n    },\n    {\n      \"name\": \"PC\",\n      \"physical\": {\n        \"lens\": {\n          \"name\": \"PC (Pebble Convex) Ø 150 mm\",\n          \"degreesMinMax\": [9, 19]\n        }\n      },\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Speed CMY / Dimmer\",\n        \"Macro CMY / Color\",\n        \"Effects\",\n        \"Zoom\",\n        \"Lamp / Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/dts/xr4-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"XR4 Spot\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"lightroom\", \"Felix Edelmann\", \"Matteo Piccina\"],\n    \"createDate\": \"2019-11-06\",\n    \"lastModifyDate\": \"2022-03-11\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-11-06\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.2)\"\n    }\n  },\n  \"physical\": {\n    \"dimensions\": [426, 590, 415],\n    \"weight\": 20,\n    \"power\": 350,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"MSD 250W\",\n      \"colorTemperature\": 8500,\n      \"lumens\": 18000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14, 14]\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://dts-lighting.it/download/xr4-spot/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Vvi90cLiRmo\"\n    ]\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#bd0091\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00c729\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#00dbfa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#f09ca1\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#5e00e3\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffe600\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#f5001c\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"direction\": \"CW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Red sun\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Blue splash\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Circular chess\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Splash\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Prickly circle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Hypnotic\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Stars\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Movement Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [11, 25],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [26, 127],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Vector mode\"\n        },\n        {\n          \"dmxRange\": [128, 247],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Reaction time to DMX signal\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Reaction time to DMX signal\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"Intensity\",\n          \"comment\": \"Intensity off\"\n        },\n        {\n          \"dmxRange\": [9, 255],\n          \"type\": \"Intensity\",\n          \"comment\": \"Intensity dark…bright\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Strobe speed slow to fast\"\n        },\n        {\n          \"dmxRange\": [140, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [180, 219],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [220, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Colour and Gobo in blackout\"\n        },\n        {\n          \"dmxRange\": [228, 233],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Pan and Tilt in blackout\"\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel Simple\": {\n      \"name\": \"Color Wheel\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [22, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [33, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [44, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [55, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [66, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [77, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [88, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [99, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [110, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [121, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [132, 142],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [143, 153],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [154, 164],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [165, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [176, 186],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [187, 197],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [198, 224],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [229, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Full Colors\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 27],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [28, 55],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [56, 83],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [84, 111],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [112, 139],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [140, 167],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [168, 195],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [196, 223],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9\n        }\n      ]\n    },\n    \"Split Colors\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [26, 51],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [52, 77],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [78, 103],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [104, 129],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [130, 155],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [156, 181],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [182, 207],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [208, 233],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9.5\n        }\n      ]\n    },\n    \"Color Wheel Rotation Angle\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        }\n      ]\n    },\n    \"Color Wheel Rotation Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 127],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [138, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Color Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Full color\",\n          \"switchChannels\": {\n            \"Color Wheel\": \"Full Colors\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Split color\",\n          \"switchChannels\": {\n            \"Color Wheel\": \"Split Colors\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Proportional color\",\n          \"switchChannels\": {\n            \"Color Wheel\": \"Color Wheel Rotation Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow\",\n          \"switchChannels\": {\n            \"Color Wheel\": \"Color Wheel Rotation Speed\"\n          }\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [26, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [52, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [78, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [104, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [130, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [156, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [182, 207],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [208, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotating\",\n          \"switchChannels\": {\n            \"Gobo / Prism Rotation\": \"Gobo / Prism Rotation Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing\",\n          \"switchChannels\": {\n            \"Gobo / Prism Rotation\": \"Gobo / Prism Rotation Speed\"\n          }\n        }\n      ]\n    },\n    \"Gobo / Prism Rotation Simple\": {\n      \"name\": \"Gobo / Prism Rotation\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 180],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [181, 202],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [203, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo / Prism Rotation Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [138, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo / Prism Rotation Angle\": {\n      \"fineChannelAliases\": [\"Gobo / Prism Rotation Angle fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo Shake\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 127],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [138, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeedStart\": \"slow reverse\",\n          \"shakeSpeedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\",\n        \"helpWanted\": \"Is the focus point near…far or far…near?\"\n      }\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 239],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Color Wheel Simple\",\n        \"Gobo Wheel\",\n        \"Gobo / Prism Rotation Simple\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Color Wheel\",\n        \"Color Mode\",\n        \"Gobo Wheel\",\n        \"Gobo Mode\",\n        \"Gobo / Prism Rotation\",\n        \"Gobo / Prism Rotation Angle fine\",\n        \"Gobo Shake\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/acl-360-roller.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ACL 360 Roller\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-06-14\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/9806/ACL%20360%20ROLLER%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/acl-360-roller\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=t_pz58uvfCs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [480.7, 541, 260],\n    \"weight\": 20,\n    \"power\": 280,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"20x 15W RGBW LEDs\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1\",  \"2\",  \"3\",  \"4\",  \"5\" ],\n        [null, null, null, null, null],\n        [\"6\",  \"7\",  \"8\",  \"9\",  \"10\"]\n      ],\n      [\n        [null, null, null, null, null],\n        [null, null, null, null, null],\n        [null, null, null, null, null]\n      ],\n      [\n        [\"11\", \"12\", \"13\", \"14\", \"15\"],\n        [null, null, null, null, null],\n        [\"16\", \"17\", \"18\", \"19\", \"20\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Pan Continuous\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Tilt Continuous\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"TiltContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"TiltContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 1\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 2\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 3\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 4\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 5\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 6\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 7\"\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 8\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 9\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 10\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 11\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 12\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 13\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 14\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 15\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 16\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 17\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 18\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 19\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 20\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 21\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 22\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 23\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 24\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 25\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 26\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 27\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 28\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 29\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 30\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 31\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 32\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 33\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 34\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 35\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 36\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 37\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 38\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 39\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 40\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 41\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 42\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 43\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 44\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 45\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 46\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 47\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 48\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 49\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 50\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 51\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 52\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 53\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 54\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 55\"\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 56\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 57\"\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 58\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 59\"\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 60\"\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 61\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 62\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 63\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 64\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\"\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 6\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 7\"\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 8\"\n        },\n        {\n          \"dmxRange\": [161, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 9\"\n        },\n        {\n          \"dmxRange\": [181, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 10\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 11\"\n        },\n        {\n          \"dmxRange\": [221, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 12\"\n        },\n        {\n          \"dmxRange\": [241, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 13\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 14\"\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Curve Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during movement\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Reset / Internal Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 79],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Normal\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motor reset\"\n        },\n        {\n          \"dmxRange\": [85, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 1 (Scene 1–8)\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 2 (Scene 9–16)\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 3 (Scene 17–24)\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 4 (Scene 25–32)\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 5 (Scene 33–40)\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 6 (Scene 41–48)\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 7 (Scene 49–56)\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"comment\": \"Each Side x4\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"comment\": \"Individual LEDs\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic\",\n      \"shortName\": \"bas\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan Continuous\",\n        \"Tilt Continuous\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Curve Mode\",\n        \"Pan/Tilt Speed\",\n        \"Reset / Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan Continuous\",\n        \"Tilt Continuous\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Curve Mode\",\n        \"Pan/Tilt Speed\",\n        \"Reset / Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan Continuous\",\n        \"Tilt Continuous\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Color Macros\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Auto Programs\",\n        \"Auto Program Speed\",\n        \"Dimmer Curve Mode\",\n        \"Pan/Tilt Speed\",\n        \"Reset / Internal Programs\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/cuepix-blinder-ww2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"CUEPIX Blinder WW2\",\n  \"categories\": [\"Blinder\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dávid Czirók\", \"István Király\"],\n    \"createDate\": \"2019-10-30\",\n    \"lastModifyDate\": \"2019-10-30\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-10-30\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.1)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/9941/Elation%20Cuepix%20Blinder%20WW2%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/cuepix-blinder-ww2\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [259.4, 181.2, 478],\n    \"weight\": 5.1,\n    \"power\": 229,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"100W Warm White COB LEDs\",\n      \"colorTemperature\": 3200\n    },\n    \"lens\": {\n      \"degreesMinMax\": [60, 60]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Left\", \"Right\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimming Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 41],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [42, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [85, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [128, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [171, 213],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [214, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Warm White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Warm White Master\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Warm White Master\",\n        \"Dimming Curve\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Warm White Master\",\n        \"Strobe\",\n        \"Dimming Curve\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Warm White Left\",\n        \"Warm White Right\",\n        \"Strobe\",\n        \"Dimming Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/cuepix-blinder-ww4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"CUEPIX Blinder WW4\",\n  \"categories\": [\"Blinder\", \"Matrix\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-10-30\",\n    \"lastModifyDate\": \"2019-10-30\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-10-30\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.1)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/9870/Elation%20Cuepix%20Blinder%20WW4%20-%20User%20Manual%20.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/cuepix-blinder-ww4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [259.4, 181.2, 478],\n    \"weight\": 5.1,\n    \"power\": 229,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"100W Warm White COB LEDs\",\n      \"colorTemperature\": 3200\n    },\n    \"lens\": {\n      \"degreesMinMax\": [60, 60]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Top-Left\", \"Top-Right\"],\n        [\"Bottom-Left\", \"Bottom-Right\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Internal Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 42],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dream\"\n        },\n        {\n          \"dmxRange\": [43, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Meteor\"\n        },\n        {\n          \"dmxRange\": [65, 87],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [88, 110],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [111, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 1\"\n        },\n        {\n          \"dmxRange\": [124, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 2\"\n        },\n        {\n          \"dmxRange\": [147, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 3\"\n        },\n        {\n          \"dmxRange\": [170, 192],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 4\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimming Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 41],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [42, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [85, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [128, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [171, 213],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [214, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Warm White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Warm White Master\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Warm White Master\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Warm White Top-Left\",\n        \"Warm White Top-Right\",\n        \"Warm White Bottom-Left\",\n        \"Warm White Bottom-Right\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Warm White Top-Left\",\n        \"Warm White Top-Right\",\n        \"Warm White Bottom-Left\",\n        \"Warm White Bottom-Right\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Warm White Top-Left\",\n        \"Warm White Top-Right\",\n        \"Warm White Bottom-Left\",\n        \"Warm White Bottom-Right\",\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Dimming Curve\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Warm White Top-Left\",\n        \"Warm White Top-Right\",\n        \"Warm White Bottom-Left\",\n        \"Warm White Bottom-Right\",\n        \"Internal Macros\",\n        \"Macro Speed\",\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Dimming Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/design-led-par-zoom.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Design LED Par Zoom\",\n  \"shortName\": \"ElationDLEDParZoom\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2019-02-21\",\n    \"lastModifyDate\": \"2019-02-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/10094/elation_design_par_led_zoom_user_manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/design-led-par-zoom\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [79, 76.5, 60],\n    \"weight\": 7,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"36× 3W LEDs (10× red, 16× green, 10× blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 49]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R02 Bastard Amber\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R04 Medium Amber\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R09 Pale Amber Gold\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R316 Gallo Gold\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R21 Golden Amber\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R26 Light Red\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R27 Medium Red\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R36 Medium Pink\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R339 Broadway Pink\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R344 Follies Pink\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R52 Light Lavender\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R54 Special Lavender\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R57 Lavender\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R59 Indigo\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R361 Hemsley Blue\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R362 Tipton Blue\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R64 Light Steel Blue\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R67 Light Sky Blue\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R68 Sky Blue\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R69 Brilliant Blue\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R76 Light Green Blue\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R79 Bright Blue\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R80 Primary Blue\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R382 Congo Blue\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R87 Pale Yellow Green\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R89 Moss Green\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R91 Primary Green\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"L200 Double CTB\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"L201 Full CTB\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"L202 1/2 CTB\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"L119 Dark Blue\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Internal Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 2\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 3\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 4\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 5\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 6\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 7\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Dimmer / Program Speed\": \"Program Speed\"\n          }\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"18Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"49deg\",\n        \"angleEnd\": \"7deg\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Internal Programs\",\n        \"Shutter / Strobe\",\n        \"Dimmer / Program Speed\",\n        \"Zoom\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/fuze-par-z60ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"FUZE PAR Z60IP\",\n  \"categories\": [\"Color Changer\", \"Dimmer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Natsuna\", \"Luke Nelson\"],\n    \"createDate\": \"2022-11-20\",\n    \"lastModifyDate\": \"2022-11-20\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.elationlighting.com/fuze-par-z60-ip\"\n    ],\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/9776/ELATION%20FUZE%20PAR%20Z60%20IP%20-%20USER%20MANUAL.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [312.5, 284, 410],\n    \"weight\": 4.5,\n    \"power\": 78,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"5deg\",\n        \"angleEnd\": \"50deg\"\n      }\n    },\n    \"Dimmer curve mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to Unit Setting\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 1\",\n          \"helpWanted\": \"What colors are each preset?\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 2\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 3\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 4\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 5\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 6\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 7\"\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 8\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 9\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 10\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 11\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 12\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 13\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 14\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 15\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 16\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 17\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 18\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 19\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 20\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 21\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 22\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 23\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 24\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 25\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 26\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 27\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 28\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 29\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 30\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 31\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 32\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 33\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 34\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 35\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 36\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 37\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 38\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 39\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 40\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 41\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 42\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 43\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 44\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 45\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 46\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 47\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 48\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 49\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 50\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 51\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 52\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 53\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 54\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 55\"\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 56\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 57\"\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 58\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 59\"\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 60\"\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 61\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 62\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 63\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Preset 64\"\n        }\n      ]\n    },\n    \"Program Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 1\",\n          \"helpWanted\": \"What do these color macros do?\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 2\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 3\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 4\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 5\"\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 6\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 7\"\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 8\"\n        },\n        {\n          \"dmxRange\": [161, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 9\"\n        },\n        {\n          \"dmxRange\": [181, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 10\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 11\"\n        },\n        {\n          \"dmxRange\": [221, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 12\"\n        },\n        {\n          \"dmxRange\": [241, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro 13\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gradient Color Macro\"\n        }\n      ]\n    },\n    \"Program Macro Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 125],\n          \"type\": \"Speed\",\n          \"speedStart\": \"-100%\",\n          \"speedEnd\": \"-1%\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [131, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"1%\",\n          \"speedEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Program Macro Fade\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel RGBW\",\n      \"shortName\": \"4ch RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"4-channel HSI\",\n      \"shortName\": \"4ch HSI\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"5-channel HSI\",\n      \"shortName\": \"5ch HSI\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Zoom\",\n        \"Dimmer curve mode\"\n      ]\n    },\n    {\n      \"name\": \"6-channel RGBW\",\n      \"shortName\": \"6ch RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"7-channel sRGBWI\",\n      \"shortName\": \"7ch sRGBWI\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Intensity\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"7-channel RGBW\",\n      \"shortName\": \"7ch RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"8-channel RGBW\",\n      \"shortName\": \"8ch RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"9-channel RGBW\",\n      \"shortName\": \"9ch RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Dimmer curve mode\"\n      ]\n    },\n    {\n      \"name\": \"10-channel 16Bit\",\n      \"shortName\": \"10ch 16Bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Zoom\",\n        \"Zoom fine\"\n      ]\n    },\n    {\n      \"name\": \"10-channel HSI\",\n      \"shortName\": \"10ch HSI\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Color Presets\",\n        \"Zoom\",\n        \"Program Macros\",\n        \"Program Macro Speed\",\n        \"Program Macro Fade\",\n        \"Dimmer curve mode\"\n      ]\n    },\n    {\n      \"name\": \"12-channel sRGBI\",\n      \"shortName\": \"12ch sRGBI\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Intensity\",\n        \"Color Presets\",\n        \"Zoom\",\n        \"Program Macros\",\n        \"Program Macro Speed\",\n        \"Program Macro Fade\",\n        \"Dimmer curve mode\"\n      ]\n    },\n    {\n      \"name\": \"13-channel RGBW\",\n      \"shortName\": \"13ch RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Presets\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Zoom\",\n        \"Program Macros\",\n        \"Program Macro Speed\",\n        \"Program Macro Fade\",\n        \"Dimmer curve mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/platinum-hfx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Platinum HFX\",\n  \"shortName\": \"PlatHFX\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-05-26\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/9814/Platinum%20HFX%20-%20User%20Manual%20.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/platinum-hfx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=87bDvuq6o-s\",\n      \"https://www.youtube.com/watch?v=Fn4PbT3aV6I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [466, 675.5, 340],\n    \"weight\": 22.7,\n    \"power\": 450,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"Philips MSD Platinum 14R 280W\"\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ed2024\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#20409a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#0ba14b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#fff200\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#d93595\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#f26522\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aqua\",\n          \"colors\": [\"#149389\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ec008c\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Quad color\",\n          \"colors\": [\"#3b59a8\", \"#f6f06b\", \"#47b749\", \"#991b1e\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00aeef\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#f26751\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB\",\n          \"colors\": [\"#c3e7ec\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#3e69b3\"]\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [29, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [38, 46],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [47, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [56, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [65, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [74, 82],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [83, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [92, 100],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [101, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [110, 118],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [119, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Beam open\"\n        },\n        {\n          \"dmxRange\": [12, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [22, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [42, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [52, 61],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [62, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [72, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [82, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [92, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [102, 112],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [113, 123],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [124, 134],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [135, 145],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [146, 156],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [157, 167],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [168, 178],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [179, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [190, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Stencil Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Stencil Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"fineChannelAliases\": [\"Static Gobo Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [22, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [36, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [43, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [57, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [71, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [78, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [85, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [92, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [99, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [106, 112],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [113, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 126],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [127, 133],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [134, 140],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 147],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [148, 154],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [155, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [162, 168],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [169, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 182],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [183, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [190, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 50],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet rotating\"\n        },\n        {\n          \"dmxRange\": [51, 69],\n          \"type\": \"Prism\",\n          \"comment\": \"linear rotating\"\n        },\n        {\n          \"dmxRange\": [70, 88],\n          \"type\": \"Prism\",\n          \"comment\": \"10-facet static\"\n        },\n        {\n          \"dmxRange\": [89, 107],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet + 10-facet\"\n        },\n        {\n          \"dmxRange\": [108, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"10-facet + linear\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 1\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 2\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 3\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 4\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 5\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 6\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 7\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 8\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 9\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 10\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 11\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 12\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 13\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 14\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"linear prism / Gobo macro 16\"\n        }\n      ]\n    },\n    \"Prism Index\": {\n      \"fineChannelAliases\": [\"Prism Index fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Auto focus\": {\n      \"fineChannelAliases\": [\"Auto focus fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 150],\n          \"type\": \"Focus\",\n          \"distance\": \"15m\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Focus\",\n          \"distance\": \"20m\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Pan / Tilt speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with Pan / Tilt movement\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout with all movement\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Special functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color change normal\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color change to any position\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"color + static-fixed Gobo change to any position\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp on\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp switch off\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"all motor reset\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan / Tilt motor reset\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo motor reset\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo motor reset\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Shutter + dimmer motor reset\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"other motor reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1 (scene 1 - 8)\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 2 (scene 9 - 16)\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 3 (scene 17 - 24)\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 4 (scene 25 - 32)\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 5 (scene 33 - 40)\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 6 (scene 41 - 48)\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 7 (scene 49 - 56)\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Gobo Stencil Rotation fine\",\n        \"Static Gobo Wheel\",\n        \"Static Gobo Wheel fine\",\n        \"Prism\",\n        \"Prism Index\",\n        \"Prism Index fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Auto focus\",\n        \"Auto focus fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Frost\",\n        \"Pan / Tilt speed\",\n        \"Special functions\"\n      ]\n    },\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Static Gobo Wheel\",\n        \"Prism\",\n        \"Prism Index\",\n        \"Focus\",\n        \"Zoom\",\n        \"Auto focus\",\n        \"Auto focus fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Frost\",\n        \"Pan / Tilt speed\",\n        \"Special functions\"\n      ]\n    },\n    {\n      \"name\": \"Basic\",\n      \"shortName\": \"basic\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Static Gobo Wheel\",\n        \"Prism\",\n        \"Prism Index\",\n        \"Focus\",\n        \"Zoom\",\n        \"Auto focus\",\n        \"Auto focus fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Frost\",\n        \"Pan / Tilt speed\",\n        \"Special functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/platinum-seven.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Platinum Seven\",\n  \"shortName\": \"Plat7\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-05\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/9777/Platinum%20Seven%20-%20User%20Manual%20.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/platinum-seven\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=-PrtJCjpubU\",\n      \"https://www.youtube.com/watch?v=8SB8obfPL0M\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [418.1, 558.9, 284.4],\n    \"weight\": 21.3,\n    \"power\": 600,\n    \"DMXconnector\": \"5-pin\",\n    \"lens\": {\n      \"degreesMinMax\": [5, 50]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null,  null,  \"O1\", null, \"O2\",     null, \"O3\", null, null],\n        [null,  null,  null, null, null,     null, null, null, null],\n        [null,  \"O12\", null, \"M1\", null,     \"M2\", null, \"O4\", null],\n        [null,  null,  null, null, null,     null, null, null, null],\n        [\"O11\", null,  \"M6\", null, \"Center\", null, \"M3\", null, \"O5\"],\n        [null,  null,  null, null, null,     null, null, null, null],\n        [null,  \"O10\", null, \"M5\", null,     \"M4\", null, \"O6\", null],\n        [null,  null,  null, null, null,     null, null, null, null],\n        [null,  null,  \"O9\", null, \"O8\",     null, \"O7\", null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Middle\": { \"name\": [\"^M[1-6]$\"] },\n      \"Outer\": { \"name\": [\"^O\\\\d+$\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Amber\": {\n      \"fineChannelAliases\": [\"Amber fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"fineChannelAliases\": [\"UV fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 39],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"],\n          \"comment\": \"Red to yellow\"\n        },\n        {\n          \"dmxRange\": [40, 71],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"Yellow to green\"\n        },\n        {\n          \"dmxRange\": [72, 103],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"],\n          \"comment\": \"Green to cyan\"\n        },\n        {\n          \"dmxRange\": [104, 135],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Cyan to blue\"\n        },\n        {\n          \"dmxRange\": [136, 167],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"],\n          \"comment\": \"Blue to magenta\"\n        },\n        {\n          \"dmxRange\": [168, 199],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"],\n          \"comment\": \"Magenta to red\"\n        },\n        {\n          \"dmxRange\": [200, 231],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"],\n          \"comment\": \"Red to white\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"4300K\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Natural white\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Full white\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaaaa\"],\n          \"comment\": \"Salmon\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaffaa\"],\n          \"comment\": \"Light green\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4682b4\"],\n          \"comment\": \"Steel blue\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaa00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e4d96f\"],\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dcd0ff\"],\n          \"comment\": \"Pale lavander\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"],\n          \"comment\": \"Red / White\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ff0000\"],\n          \"comment\": \"Green / Red\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ff0000\"],\n          \"comment\": \"Blue / Red\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#ff0000\"],\n          \"comment\": \"White / Red\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#ffaaaa\"],\n          \"comment\": \"White / Pink\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#40e0d0\"],\n          \"comment\": \"White / Turqouise\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"],\n          \"comment\": \"Small Red / White\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CRI=85\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CRI=90\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CRI=95\"\n        },\n        {\n          \"dmxRange\": [165, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Color Presets Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Mode\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to setting on fixture\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"5deg\",\n        \"angleEnd\": \"50deg\"\n      }\n    },\n    \"Chase Patterns\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No function (LEDs off)\"\n        },\n        {\n          \"dmxRange\": [15, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [31, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [47, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [63, 78],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [79, 94],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 5\"\n        },\n        {\n          \"dmxRange\": [95, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 6\"\n        },\n        {\n          \"dmxRange\": [111, 126],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 7\"\n        },\n        {\n          \"dmxRange\": [127, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 8\"\n        },\n        {\n          \"dmxRange\": [143, 158],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 9\"\n        },\n        {\n          \"dmxRange\": [159, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 10\"\n        },\n        {\n          \"dmxRange\": [175, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 11\"\n        },\n        {\n          \"dmxRange\": [191, 206],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 12\"\n        },\n        {\n          \"dmxRange\": [207, 222],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 13\"\n        },\n        {\n          \"dmxRange\": [223, 238],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 14\"\n        },\n        {\n          \"dmxRange\": [239, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 15\"\n        }\n      ]\n    },\n    \"Chase Pattern Speed\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 125],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [131, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Chase Fade\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\",\n        \"helpWanted\": \"Correct direction?\"\n      }\n    },\n    \"White Balance\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 189],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [190, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Edit new White Balance setting\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Save new White Balance setting\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while movement\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Special Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Change Normal\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all motors\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset scan motor\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent mode on\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Edit and save White Balance\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent mode off\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset other motors\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 1 (Scene 1-8)\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 2 (Scene 9-16)\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 3 (Scene 17-24)\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 4 (Scene 25-32)\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 5 (Scene 33-40)\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 6 (Scene 41-48)\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 7 (Scene 49-56)\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Unknown\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Cyan $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Cyan\",\n        \"UV\",\n        \"Color Macros\",\n        \"Color Presets\",\n        \"Color Presets Dimmer\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer Mode\",\n        \"Zoom\",\n        \"Chase Patterns\",\n        \"Chase Pattern Speed\",\n        \"Chase Fade\",\n        \"White Balance\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\"\n      ]\n    },\n    {\n      \"name\": \"Standard\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Amber\",\n        \"Amber fine\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"UV\",\n        \"UV fine\",\n        \"Color Macros\",\n        \"Color Presets\",\n        \"Color Presets Dimmer\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer Mode\",\n        \"Zoom\",\n        \"Chase Patterns\",\n        \"Chase Pattern Speed\",\n        \"Chase Fade\",\n        \"White Balance\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Center\", \"Middle\", \"Outer\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\",\n            \"Cyan $pixelKey\",\n            \"UV $pixelKey\"\n          ]\n        },\n        \"Color Macros\",\n        \"Color Presets\",\n        \"Color Presets Dimmer\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimmer Mode\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Chase Patterns\",\n        \"Chase Pattern Speed\",\n        \"Chase Fade\",\n        \"White Balance\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/platinum-spot-15r-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Platinum Spot 15R Pro\",\n  \"shortName\": \"PlatSpot15rPro\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-05-23\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/10038/PLATINUM%20SPOT%2015R%20PRO%20-%20User%20Manual%20Ver.1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/platinum-spot-15r-pro\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=gwEywBRndOU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [50, 72, 46.5],\n    \"weight\": 22.2,\n    \"power\": 500,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Philips Platinum 15R\"\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [19, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [38, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [57, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [76, 94],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [95, 113],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [114, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"fineChannelAliases\": [\"Magenta fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"fineChannelAliases\": [\"Yellow fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Rotating Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [120, 134],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [135, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [165, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [180, 194],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [195, 209],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Stencil Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Stencil Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"fineChannelAliases\": [\"Static Gobo Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [120, 126],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [127, 133],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [134, 140],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 147],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [148, 154],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [155, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [162, 168],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [169, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 182],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [183, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [190, 196],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [197, 203],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [204, 210],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [211, 217],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [218, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Prism/Gobo Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\"\n        },\n        {\n          \"dmxRange\": [32, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotating\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        }\n      ]\n    },\n    \"Rotating Prism\": {\n      \"fineChannelAliases\": [\"Rotating Prism fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"13Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"highlightValue\": 65535,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Iris\": {\n      \"fineChannelAliases\": [\"Iris fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"open\",\n          \"openPercentEnd\": \"closed\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"off\",\n          \"frostIntensityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [224, 254],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Color Macro Speed\": {\n      \"highlightValue\": 127,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by movement\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout by all wheel changing\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 28\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 29\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 30\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY\"\n        }\n      ]\n    },\n    \"Maintenance / Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colour change normal\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colour change to any position\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colour & gobo change to any position\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp switch off\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motor reset\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Scan motor reset\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colors motor reset\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo motor reset\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Shutter & Dimmer motor reset\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Other motor reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 2\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 3\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 4\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 5\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 6\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 7\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Control\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Static Gobo Wheel\",\n        \"Prism/Gobo Macros\",\n        \"Rotating Prism\",\n        \"Focus\",\n        \"Zoom\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Iris\",\n        \"Frost\",\n        \"Color Macro Speed\",\n        \"Pan/Tilt Speed\",\n        \"Color Macros\",\n        \"Maintenance / Programs\"\n      ]\n    },\n    {\n      \"name\": \"Standard\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Static Gobo Wheel\",\n        \"Prism/Gobo Macros\",\n        \"Rotating Prism\",\n        \"Focus\",\n        \"Zoom\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Iris\",\n        \"Frost\",\n        \"Color Macro Speed\",\n        \"Pan/Tilt Speed\",\n        \"Color Macros\",\n        \"Maintenance / Programs\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Gobo Stencil Rotation fine\",\n        \"Static Gobo Wheel\",\n        \"Static Gobo Wheel fine\",\n        \"Prism/Gobo Macros\",\n        \"Rotating Prism\",\n        \"Rotating Prism fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Iris\",\n        \"Iris fine\",\n        \"Frost\",\n        \"Color Macro Speed\",\n        \"Pan/Tilt Speed\",\n        \"Color Macros\",\n        \"Maintenance / Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/proteus-hybrid.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Proteus Hybrid\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"MeroChat\"],\n    \"createDate\": \"2019-05-21\",\n    \"lastModifyDate\": \"2026-01-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/10677/ELATION%20PROTEUS%20HYBRID%20-%20PROTEUS%20HYBRID%20WMG%20-%20USER%20MANUAL.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/proteus-hybrid\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=w_GtudSQ8BU\",\n      \"https://www.youtube.com/watch?v=TPU1p4mMNlo&t=20\",\n      \"https://www.youtube.com/watch?v=v8iZYjFaTDA\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 22\n  },\n  \"physical\": {\n    \"dimensions\": [465, 650, 571],\n    \"weight\": 38.0,\n    \"power\": 750,\n    \"DMXconnector\": \"5-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"Philips MSD Platinum 21R 470W\",\n      \"colorTemperature\": 8000,\n      \"lumens\": 23000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [2, 40]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ec252a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#2d3691\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#14a651\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#f7ef22\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#8f298d\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aqua\",\n          \"colors\": [\"#1aa89c\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#f16726\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light pink\",\n          \"colors\": [\"#f5abcc\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lime green\",\n          \"colors\": [\"#6cbd47\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light yellow\",\n          \"colors\": [\"#f5ed33\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ea098d\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB\",\n          \"colors\": [\"#b1d6f1\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#e7a45d\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#572e8a\"]\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"10%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"25%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"40%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"55%\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 7\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 8\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 9\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 10\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 11\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 12\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 13\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 14\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"AnimationGoboStart\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"fineChannelAliases\": [\"Magenta fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"fineChannelAliases\": [\"Yellow fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"fineChannelAliases\": [\"CTO fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"default\",\n        \"colorTemperatureEnd\": \"CTO\"\n      }\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Beam\"\n        },\n        {\n          \"dmxRange\": [11, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"comment\": \"Spot\"\n        },\n        {\n          \"dmxRange\": [22, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [42, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [52, 61],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [62, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [72, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [82, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [92, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [102, 112],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [113, 123],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [124, 134],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [135, 145],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [146, 156],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [157, 167],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [168, 178],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [179, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [190, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Correct angle?\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"fineChannelAliases\": [\"Static Gobo Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [15, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [29, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [36, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [43, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [50, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [57, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [64, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [71, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [78, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [85, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [92, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [99, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [106, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 117],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [118, 123],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [124, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [130, 135],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [136, 141],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [142, 147],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [148, 153],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [154, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 165],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [166, 171],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [172, 177],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [178, 183],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [184, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [190, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotating Prism / Prism/Gobo Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 64],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet prism\"\n        },\n        {\n          \"dmxRange\": [65, 94],\n          \"type\": \"Prism\",\n          \"comment\": \"4-facet linear prism\"\n        },\n        {\n          \"dmxRange\": [95, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet + 4-facet prisms\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 1\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 2\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 3\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 4\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 5\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 6\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 7\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 8\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 9\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 10\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 11\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 12\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 13\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 14\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 16\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"fineChannelAliases\": [\"Prism Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Correct angle?\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Auto Focus\": {\n      \"fineChannelAliases\": [\"Auto Focus fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [51, 150],\n          \"type\": \"Focus\",\n          \"distance\": \"15m\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Focus\",\n          \"distance\": \"20m\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [136, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"CMY Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"CMY Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Random CMY\"\n        }\n      ]\n    },\n    \"Pan / Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at movement\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at all wheel movement\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Maintenance / Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color wheel change normal\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color wheel change to any position\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color / Fixed gobo wheel change to any position\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All motors reset\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Scan motor reset\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color wheel motor reset\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo wheel motor reset\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Shutter/dimmer motor reset\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Other motors reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 1\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 2\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 3\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 4\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 5\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 6\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 7\"\n        },\n        {\n          \"dmxRange\": [240, 241],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curce standard\"\n        },\n        {\n          \"dmxRange\": [242, 243],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curce linear\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curce square\"\n        },\n        {\n          \"dmxRange\": [246, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curce inverse square\"\n        },\n        {\n          \"dmxRange\": [248, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curce s-curve\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic\",\n      \"shortName\": \"bas\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Static Gobo Wheel\",\n        \"Rotating Prism / Prism/Gobo Macros\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Zoom\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Frost\",\n        \"Animation Wheel\",\n        \"CMY Speed\",\n        \"CMY Macros\",\n        \"Pan / Tilt Speed\",\n        \"Maintenance / Programs\"\n      ]\n    },\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Static Gobo Wheel\",\n        \"Rotating Prism / Prism/Gobo Macros\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Zoom\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Frost\",\n        \"Animation Wheel\",\n        \"CMY Speed\",\n        \"CMY Macros\",\n        \"Pan / Tilt Speed\",\n        \"Maintenance / Programs\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\",\n        \"CTO\",\n        \"CTO fine\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Static Gobo Wheel\",\n        \"Static Gobo Wheel fine\",\n        \"Rotating Prism / Prism/Gobo Macros\",\n        \"Prism Rotation\",\n        \"Prism Rotation fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Auto Focus\",\n        \"Auto Focus fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Frost\",\n        \"Animation Wheel\",\n        \"CMY Speed\",\n        \"CMY Macros\",\n        \"Pan / Tilt Speed\",\n        \"Maintenance / Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/sixpar-100-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SIXPAR 100IP\",\n  \"shortName\": \"Sixpar100IP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-01-02\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"comment\": \"IP65 proof\",\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/9890/Elation%20Sixpar%20100%20IP%20%20100WMG%20-%20User%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/sixpar-100ip\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vLJvunbVWIU\",\n      \"https://www.youtube.com/watch?v=oZdkqF0vT1I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [257, 243, 158],\n    \"weight\": 4.3,\n    \"power\": 89,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"7x12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RG\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RUV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GW\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GA\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GUV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BA\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BUV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"AUV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGW\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGA\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGUV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBUV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RAUV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBW\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBA\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBUV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWA\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GAUV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWUV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BAUV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWA\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGAUV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWA\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWUV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBAUV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWAUV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWUV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBAUV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWAUV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWAUV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWA\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWAUV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWAUV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWAUV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWAUV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Chase Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"30 colors\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimming Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Chase Macros\",\n        \"Color Chase Speed\",\n        \"Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/sixpar-100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SIXPAR 100\",\n  \"shortName\": \"Sixpar100\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-01-02\",\n    \"lastModifyDate\": \"2019-01-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/9887/Elation%20Sixpar%20100%20-%20User%20Manual%202022-02-21.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/sixpar-100\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vLJvunbVWIU\",\n      \"https://www.youtube.com/watch?v=oZdkqF0vT1I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [257, 243, 125],\n    \"weight\": 3.3,\n    \"power\": 89,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"7x12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RG\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RUV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GW\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GA\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GUV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BA\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BUV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"AUV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGW\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGA\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGUV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBUV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RAUV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBW\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBA\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBUV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWA\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GAUV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWUV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BAUV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWA\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGAUV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWA\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWUV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBAUV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWAUV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWUV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBAUV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWAUV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWAUV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWA\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWAUV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWAUV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWAUV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWAUV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Chase Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"30 colors\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimming Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Chase Macros\",\n        \"Color Chase Speed\",\n        \"Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/sixpar-200-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SIXPAR 200 IP\",\n  \"shortName\": \"Sixpar200IP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-01-02\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"comment\": \"IP65 proof\",\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/9889/ELATION%20SIXPAR%20200IP%20&%20WMG%20-%20USER%20MANUAL.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/sixpar-200ip\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vLJvunbVWIU\",\n      \"https://www.youtube.com/watch?v=qQ3m_RDZoMg\",\n      \"https://www.youtube.com/watch?v=oZdkqF0vT1I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [313, 300, 157],\n    \"weight\": 5.7,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"12x12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RG\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RUV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GW\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GA\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GUV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BA\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BUV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"AUV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGW\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGA\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGUV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBUV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RAUV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBW\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBA\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBUV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWA\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GAUV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWUV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BAUV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWA\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGAUV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWA\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWUV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBAUV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWAUV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWUV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBAUV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWAUV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWAUV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWA\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWAUV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWAUV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWAUV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWAUV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Chase Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"30 colors\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimming Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Chase Macros\",\n        \"Color Chase Speed\",\n        \"Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/sixpar-200-wmg.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SIXPAR 200 WMG\",\n  \"shortName\": \"Sixpar200WMG\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-01-02\",\n    \"lastModifyDate\": \"2019-01-02\"\n  },\n  \"comment\": \"IP65 proof with White Marine Grade exterior coating designed for the marine/coastal environment installations\",\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/11387/ELATION%20SIXPAR%20SERIES%20-%20DMX%20TRAITS.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/sixpar-200wmg\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vLJvunbVWIU\",\n      \"https://www.youtube.com/watch?v=oZdkqF0vT1I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [313, 300, 157],\n    \"weight\": 5.7,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"12x12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [23, 23]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RG\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RUV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GW\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GA\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GUV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BA\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BUV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"AUV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGW\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGA\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGUV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBUV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RAUV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBW\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBA\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBUV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWA\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GAUV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWUV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BAUV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWA\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGAUV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWA\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWUV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBAUV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWAUV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWUV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBAUV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWAUV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWAUV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWA\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWAUV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWAUV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWAUV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWAUV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Chase Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"30 colors\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimming Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Chase Macros\",\n        \"Color Chase Speed\",\n        \"Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/sixpar-200.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SIXPAR 200\",\n  \"shortName\": \"Sixpar200\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-01-02\",\n    \"lastModifyDate\": \"2019-01-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/9852/Elation%20Sixpar%20200%20-%20User%20Manual%202022-02-21.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/sixpar-200\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vLJvunbVWIU\",\n      \"https://www.youtube.com/watch?v=oZdkqF0vT1I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [313, 300, 125],\n    \"weight\": 4.9,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"12x12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RG\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RUV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GW\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GA\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GUV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BA\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BUV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"AUV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGW\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGA\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGUV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBUV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RAUV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBW\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBA\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBUV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWA\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GAUV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWUV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BAUV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWA\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGAUV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWA\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWUV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBAUV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWAUV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWUV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBAUV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWAUV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWAUV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWA\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWAUV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWAUV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWAUV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWAUV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Chase Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"30 colors\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimming Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Chase Macros\",\n        \"Color Chase Speed\",\n        \"Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/sixpar-300-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SIXPAR 300 IP\",\n  \"shortName\": \"Sixpar300IP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-01-02\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"comment\": \"IP65 proof\",\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/9888/ELATION%20SIXPAR%20300IP%20&%20WMG%20-%20USER%20MANUAL.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/sixpar-300ip\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vLJvunbVWIU\",\n      \"https://www.youtube.com/watch?v=oZdkqF0vT1I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [365, 365, 157],\n    \"weight\": 9.5,\n    \"power\": 220,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"18x12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RG\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RUV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GW\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GA\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GUV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BA\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BUV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"AUV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGW\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGA\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGUV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBUV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RAUV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBW\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBA\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBUV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWA\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GAUV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWUV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BAUV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWA\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGAUV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWA\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWUV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBAUV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWAUV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWUV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBAUV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWAUV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWAUV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWA\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWAUV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWAUV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWAUV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWAUV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Chase Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"30 colors\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimming Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Chase Macros\",\n        \"Color Chase Speed\",\n        \"Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/sixpar-300-wmg.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SIXPAR 300 WMG\",\n  \"shortName\": \"Sixpar300WMG\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-01-02\",\n    \"lastModifyDate\": \"2019-01-02\"\n  },\n  \"comment\": \"IP65 proof with White Marine Grade exterior coating designed for the marine/coastal environment installations\",\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/11388/ELATION%20SIXPAR%20SERIES%20-%20DMX%20TRAITS.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/sixpar-300wmg\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vLJvunbVWIU\",\n      \"https://www.youtube.com/watch?v=oZdkqF0vT1I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [365, 365, 157],\n    \"weight\": 8.7,\n    \"power\": 220,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"18x12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [23, 23]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RG\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RUV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GW\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GA\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GUV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BA\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BUV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"AUV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGW\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGA\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGUV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBUV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RAUV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBW\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBA\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBUV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWA\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GAUV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWUV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BAUV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWA\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGAUV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWA\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWUV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBAUV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWAUV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWUV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBAUV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWAUV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWAUV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWA\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWAUV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWAUV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWAUV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWAUV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Chase Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"30 colors\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimming Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Chase Macros\",\n        \"Color Chase Speed\",\n        \"Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/sixpar-300.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SIXPAR 300\",\n  \"shortName\": \"Sixpar300\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-01-02\",\n    \"lastModifyDate\": \"2019-01-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/9851/Elation%20Sixpar%20300%20-%20User%20Manual%202022-02-21.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/sixpar-300\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vLJvunbVWIU\",\n      \"https://www.youtube.com/watch?v=oZdkqF0vT1I\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [365, 365, 125],\n    \"weight\": 8.1,\n    \"power\": 220,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"18x12W RGBAWUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"R\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"G\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"B\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"W\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RG\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RUV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GB\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GW\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GA\",\n          \"colors\": [\"#92ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GUV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BA\",\n          \"colors\": [\"#ffbfff\"]\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BUV\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"AUV\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGW\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGA\",\n          \"colors\": [\"#ffdf00\"]\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGUV\",\n          \"colors\": [\"#ffff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA\",\n          \"colors\": [\"#ff6080\"]\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBUV\",\n          \"colors\": [\"#ff00ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA\",\n          \"colors\": [\"#ff9555\"]\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RAUV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBW\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBA\",\n          \"colors\": [\"#92ff92\"]\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBUV\",\n          \"colors\": [\"#00ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWA\",\n          \"colors\": [\"#baff5d\"]\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWUV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GAUV\",\n          \"colors\": [\"#92ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"]\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWUV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BAUV\",\n          \"colors\": [\"#ffbfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"WAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBA\",\n          \"colors\": [\"#ffdf80\"]\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWA\",\n          \"colors\": [\"#ffea55\"]\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGAUV\",\n          \"colors\": [\"#ffdf00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWA\",\n          \"colors\": [\"#ff95aa\"]\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWUV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBAUV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWAUV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"]\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWUV\",\n          \"colors\": [\"#80ffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBAUV\",\n          \"colors\": [\"#92ff92\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GWAUV\",\n          \"colors\": [\"#baff5d\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWAUV\",\n          \"colors\": [\"#ffdfff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWA\",\n          \"colors\": [\"#ffeaaa\"]\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWUV\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBAUV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGWAUV\",\n          \"colors\": [\"#ffea55\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBWAUV\",\n          \"colors\": [\"#ff95aa\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWAUV\",\n          \"colors\": [\"#baffba\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBWAUV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Color Chase Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"30 colors\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6 colors\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [81, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimming Modes\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Color Chase Macros\",\n        \"Color Chase Speed\",\n        \"Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/uni-bar.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"UNI BAR\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Homemdamesadeluz\"],\n    \"createDate\": \"2019-06-17\",\n    \"lastModifyDate\": \"2019-06-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/10326/elation_UNI-BAR_user_manual_090216.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/uni-bar\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 66.8, 82],\n    \"weight\": 1.1,\n    \"power\": 1200,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Dimmer\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/elation/zw19.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ZW19\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-05-13\",\n    \"lastModifyDate\": \"2022-05-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://d295jznhem2tn9.cloudfront.net/ItemRelatedFiles/9786/elation_ZW19_user_manual_ver%201-092015.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.elationlighting.com/zw19\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [206, 395, 321],\n    \"weight\": 8.6,\n    \"power\": 245,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"19× 10W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"220deg\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2700K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 1\"\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 2\"\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 3\"\n        },\n        {\n          \"dmxRange\": [13, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 4\"\n        },\n        {\n          \"dmxRange\": [17, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 5\"\n        },\n        {\n          \"dmxRange\": [21, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 6\"\n        },\n        {\n          \"dmxRange\": [25, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 7\"\n        },\n        {\n          \"dmxRange\": [29, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 8\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 9\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 10\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 11\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 12\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 13\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 14\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 15\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 16\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 17\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 18\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 19\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 20\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 21\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 22\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 23\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 24\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 25\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 26\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 27\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 28\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 29\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 30\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 31\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 32\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 33\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 34\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 35\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 36\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 37\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 38\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 39\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 40\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 41\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 42\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 43\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 44\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 45\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 46\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 47\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 48\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 49\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 50\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 51\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 52\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 53\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 54\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 55\"\n        },\n        {\n          \"dmxRange\": [221, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 56\"\n        },\n        {\n          \"dmxRange\": [225, 228],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 57\"\n        },\n        {\n          \"dmxRange\": [229, 232],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 58\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 59\"\n        },\n        {\n          \"dmxRange\": [237, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 60\"\n        },\n        {\n          \"dmxRange\": [241, 244],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 61\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 62\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 63\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macro 64\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [25, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [230, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimming Curve Modes\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default to unit setting\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"10deg\",\n        \"angleEnd\": \"60deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Reset / Dimming Modes\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout While Pan/Tilt Movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout When RGBW Values Change\"\n        },\n        {\n          \"dmxRange\": [100, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset All\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Temperature\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimming Curve Modes\",\n        \"Zoom\",\n        \"Pan/Tilt Speed\",\n        \"Reset / Dimming Modes\"\n      ]\n    },\n    {\n      \"name\": \"22-channel\",\n      \"shortName\": \"22ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Color Temperature\",\n        \"Color Macros\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimming Curve Modes\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Pan/Tilt Speed\",\n        \"Reset / Dimming Modes\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eliminator/stealth-beam.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stealth Beam\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"George Qualley IV\"],\n    \"createDate\": \"2017-09-19\",\n    \"lastModifyDate\": \"2018-09-04\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2017-09-19\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.0)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/13271/Stealth%20Beam%20(1st%20Ed.).pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/stealth-beam\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=A2l0YIFRARA\",\n      \"https://www.youtube.com/watch?v=vMqesfl5Fsk\"\n    ]\n  },\n  \"helpWanted\": \"The second mode is named \\\"16-channel\\\" in the manual, but contains 17 channels. What is the correct channel list?\",\n  \"physical\": {\n    \"dimensions\": [239, 285, 146],\n    \"weight\": 3.8,\n    \"power\": 75,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1x 60W RGBW 4-in-1 LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [11, 11]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 17],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [18, 27],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [28, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [38, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [48, 57],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Red/Green\"\n        },\n        {\n          \"dmxRange\": [58, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Green/Blue\"\n        },\n        {\n          \"dmxRange\": [68, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8080ff\"],\n          \"comment\": \"Blue/White\"\n        },\n        {\n          \"dmxRange\": [78, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8080\"],\n          \"comment\": \"Red/White\"\n        },\n        {\n          \"dmxRange\": [88, 97],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red/Green/Blue\"\n        },\n        {\n          \"dmxRange\": [98, 107],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ffff\"],\n          \"comment\": \"Green/Blue/White\"\n        },\n        {\n          \"dmxRange\": [108, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff80ff\"],\n          \"comment\": \"Red/Blue/White\"\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff80\"],\n          \"comment\": \"Red/Green/White\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red/Green/Blue/White\"\n        },\n        {\n          \"dmxRange\": [138, 188],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [189, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [5, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Pan Continuous Movement\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Pan Movement Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Tilt Movement Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt movement forth and back\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Change / Fade Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pan/Tilt Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [33, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [59, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [85, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [111, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [137, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [163, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [189, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [215, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Pan/Tilt Program Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Set High Speed Mode\",\n          \"hold\": \"10s\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Set Low Speed Mode\",\n          \"hold\": \"10s\"\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"10s\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Macro\",\n        \"Color Change / Fade Speed\",\n        \"Pan/Tilt Programs\"\n      ]\n    },\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macro\",\n        \"Master Dimmer\",\n        \"Shutter / Strobe\",\n        \"Pan Continuous Movement\",\n        \"Pan Movement Speed\",\n        \"Tilt Movement Macro\",\n        \"Color Change / Fade Speed\",\n        \"Pan/Tilt Programs\",\n        \"Pan/Tilt Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eliminator/stealth-wash-zoom.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stealth Wash Zoom\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\", \"JonahKr\"],\n    \"createDate\": \"2019-01-05\",\n    \"lastModifyDate\": \"2021-09-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdb.s3.amazonaws.com/ItemRelatedFiles/13274/Stealth%20Wash%20Zoom%20User%20Manual%20Revised%20092018.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.adj.com/stealth-wash-zoom\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=M7ALeJ3_jGc\",\n      \"https://www.youtube.com/watch?v=ubeWU8-BfNI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [234, 321, 158],\n    \"weight\": 4.5,\n    \"power\": 95,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7× 12W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green aka Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue aka Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + White\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue aka Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + White\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + White\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue aka White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White\",\n          \"colors\": [\"#ffff55\"]\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + White\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White aka brighter White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [76, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Internal Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [161, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [181, 200],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [201, 225],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"4deg\",\n        \"angleEnd\": \"45deg\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 245],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros 2\": {\n      \"name\": \"Color Macros\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green aka Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue aka Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + White\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue aka Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + White\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + White\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue aka White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White\",\n          \"colors\": [\"#ffff55\"]\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + White\",\n          \"colors\": [\"#55ffff\"]\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White aka brighter White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"warm\",\n        \"colorTemperatureEnd\": \"cold\"\n      }\n    },\n    \"Color Fade\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Macros\",\n        \"Internal Programs\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Zoom\",\n        \"Color Temperature\",\n        \"Color Macros 2\",\n        \"Color Fade\",\n        \"Pan/Tilt Speed\",\n        \"Internal Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/empire-lighting/8x-3w-led-spider-effect.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"8x 3W LED Spider Effect\",\n  \"categories\": [\"Effect\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Tobias König\"],\n    \"createDate\": \"2019-10-16\",\n    \"lastModifyDate\": \"2019-10-16\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-10-16\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.2)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://forum.dmxcontrol-projects.org/core/index.php?attachment/12216-empire-lighting-led-spider-effekt-pdf/\"\n    ]\n  },\n  \"physical\": {\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"LED 1\", \"LED 2\", \"LED 3\", \"LED 4\"],\n        [   null,    null,    null,    null],\n        [\"LED 5\", \"LED 6\", \"LED 7\", \"LED 8\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Head 1\": [\"LED 1\", \"LED 2\", \"LED 3\", \"LED 4\"],\n      \"Head 2\": [\"LED 5\", \"LED 6\", \"LED 7\", \"LED 8\"],\n      \"Left\": [\"LED 1\", \"LED 5\"],\n      \"Middle-Left\": [\"LED 2\", \"LED 6\"],\n      \"Middle-Right\": [\"LED 3\", \"LED 7\"],\n      \"Right\": [\"LED 4\", \"LED 8\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [8, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music mode\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Tilt $pixelKey\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Tilt Head 1\",\n        \"Tilt Head 2\",\n        \"Tilt Speed\",\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red Left\",\n        \"Green Middle-Left\",\n        \"Blue Middle-Right\",\n        \"White Right\",\n        \"Mode\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Tilt Head 1\",\n        \"Tilt Head 2\",\n        \"Tilt Speed\",\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red LED 1\",\n        \"Green LED 2\",\n        \"Blue LED 3\",\n        \"White LED 4\",\n        \"Red LED 5\",\n        \"Green LED 6\",\n        \"Blue LED 7\",\n        \"White LED 8\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/epsilon/duo-q-beam-bar.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Duo Q-Beam Bar\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-11-09\",\n    \"lastModifyDate\": \"2018-11-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.dropbox.com/s/xi9w0jebel81c8q/Epsilon%20-%20DUO%20Q-BEAM%20BAR.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.epsilon-pro.com/lights-duo-q-beam-bar.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=NIiO0SIy4qU\",\n      \"https://www.youtube.com/watch?v=JkoFxqO17JM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1065, 95, 177],\n    \"weight\": 8.7,\n    \"power\": 110,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"8 × 10W CREE RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [3, 3]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1\", \"2\", \"3\", \"4\", null, \"5\", \"6\", \"7\", \"8\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Left Bar\": [\"1\", \"2\", \"3\", \"4\"],\n      \"Right Bar\": [\"5\", \"6\", \"7\", \"8\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Internal Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 1\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 2\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 3\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 4\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 5\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 6\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 7\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 8\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 9\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in program Show 10\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Is the program speed slow…fast or fast…slow?\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Tilt\": {\n      \"defaultValue\": 180,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\",\n        \"helpWanted\": \"Is the bar at 0°/90°/180° tilt angles for DMX values 0/180/255, respectively? The manual is unclear here.\"\n      }\n    },\n    \"$pixelKey Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"LED $pixelKey Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"LED $pixelKey Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"LED $pixelKey Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"LED $pixelKey White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"36-channel\",\n      \"shortName\": \"36ch\",\n      \"channels\": [\n        \"Left Bar Tilt\",\n        \"Left Bar Speed\",\n        \"Right Bar Tilt\",\n        \"Right Bar Speed\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"LED $pixelKey Red\",\n            \"LED $pixelKey Green\",\n            \"LED $pixelKey Blue\",\n            \"LED $pixelKey White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"40-channel\",\n      \"shortName\": \"40ch\",\n      \"channels\": [\n        \"Left Bar Tilt\",\n        \"Left Bar Speed\",\n        \"Right Bar Tilt\",\n        \"Right Bar Speed\",\n        \"Master Dimmer\",\n        \"Internal Programs\",\n        \"Program Speed\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"LED $pixelKey Red\",\n            \"LED $pixelKey Green\",\n            \"LED $pixelKey Blue\",\n            \"LED $pixelKey White\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/equinox/gigabar.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Gigabar\",\n  \"categories\": [\"Stand\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Justin Hornsby\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-11-16\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.prolight.co.uk/ftp-in/EQLED65_Manual.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=MndFfN5n__8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1000, 320, 82],\n    \"weight\": 13,\n    \"power\": 135,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4x30W tri-color COB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"1&2\": [\"1\", \"2\"],\n      \"3&4\": [\"3\", \"4\"],\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"RedGreen\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"GreenBlue\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"RedBlue\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"RedGreenBlue\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"What colors are Color 1 until Color 8?\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Master Dimmer\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dream\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Meteor\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 1\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 2\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 3\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 4\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 5\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 6\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 7\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 8\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 9\",\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Master Dimmer / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Flash\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Sound Sensitivity / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"PowerOutput 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"OFF\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ON\"\n        }\n      ]\n    },\n    \"PowerOutput 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"OFF\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ON\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Colors $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"R\"\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"G\"\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"B\"\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"RG\"\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"RB\"\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"GB\"\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"RGB\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"4ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Colors $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"5ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"PowerOutput 1\",\n        \"PowerOutput 2\"\n      ]\n    },\n    {\n      \"name\": \"6ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1&2\", \"3&4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Master Dimmer\",\n        \"Sound Sensitivity / Strobe\",\n        \"PowerOutput 1\",\n        \"PowerOutput 2\"\n      ]\n    },\n    {\n      \"name\": \"8ch\",\n      \"channels\": [\n        \"Programs\",\n        \"Master Dimmer / Program Speed / Sound Sensitivity\",\n        \"Flash\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"PowerOutput 1\",\n        \"PowerOutput 2\"\n      ]\n    },\n    {\n      \"name\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"17ch\",\n      \"channels\": [\n        \"Programs\",\n        \"Master Dimmer / Program Speed / Sound Sensitivity\",\n        \"Flash\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"PowerOutput 1\",\n        \"PowerOutput 2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/equinox/rgb-power-batten.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RGB Power Batten\",\n  \"shortName\": \"EQLED032\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Phill\"],\n    \"createDate\": \"2019-04-07\",\n    \"lastModifyDate\": \"2019-04-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.prolight.co.uk/ftp-in/EQLED032A_Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20220118184538/https://prolight.co.uk/product/rgb-power-batten\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1075, 85, 65],\n    \"weight\": 1.8,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"240x 10mm LEDs (96x red, 72x green, 72x blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [125, 50, 10],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Segment 1\", \"Segment 2\", \"Segment 3\", \"Segment 4\", \"Segment 6\", \"Segment 5\", \"Segment 7\", \"Segment 8\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Segments 1&2\": [\"Segment 1\", \"Segment 2\"],\n      \"Segments 3&4\": [\"Segment 3\", \"Segment 4\"],\n      \"Segments 5&6\": [\"Segment 5\", \"Segment 6\"],\n      \"Segments 7&8\": [\"Segment 7\", \"Segment 8\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 21\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Effect\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Flash\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"50Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off? Is the frequency of 50Hz correct?\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-Channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Function\",\n        \"Effect Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"3-Channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"4-Channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"7-Channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Function\",\n        \"Effect Speed / Sound Sensitivity\",\n        \"Flash\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"14-Channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Segments 1&2\", \"Segments 3&4\", \"Segments 5&6\", \"Segments 7&8\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Flash\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"26-Channel\",\n      \"shortName\": \"26ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Flash\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/colorsource-par-deep-blue.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ColorSource PAR Deep Blue\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-10-30\",\n    \"lastModifyDate\": \"2019-10-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737484145\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737494638\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/ColorSource-PAR/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=8yZygyTDANU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [203, 310, 240],\n    \"weight\": 3.77,\n    \"power\": 90,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"40 Lumileds LUXEON Z LED\",\n      \"lumens\": 2429\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14.5, 14.5]\n    }\n  },\n  \"rdm\": {\n    \"modelId\": 514\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"33Hz\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5 Channel (Default)\",\n      \"shortName\": \"5ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Indigo\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"Direct\",\n      \"shortName\": \"dir\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Indigo\",\n        \"Lime\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"1 Channel\",\n      \"shortName\": \"1ch\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"rgb\",\n      \"rdmPersonalityIndex\": 4,\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Indigo\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/colorsource-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ColorSource PAR\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Joseph Gates\"],\n    \"createDate\": \"2019-10-30\",\n    \"lastModifyDate\": \"2019-10-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737484145\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737494638\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/ColorSource-PAR/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=8yZygyTDANU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [203, 310, 240],\n    \"weight\": 3.77,\n    \"power\": 90,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"40 Lumileds LUXEON Z LED\",\n      \"lumens\": 3039\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14.5, 14.5]\n    }\n  },\n  \"rdm\": {\n    \"modelId\": 513\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"33Hz\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5 Channel (Default)\",\n      \"shortName\": \"5ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"Direct\",\n      \"shortName\": \"dir\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Lime\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"1 Channel\",\n      \"shortName\": \"1ch\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"rgb\",\n      \"rdmPersonalityIndex\": 4,\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/colorsource-spot-deep-blue.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ColorSource Spot Deep Blue\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-10-21\",\n    \"lastModifyDate\": \"2019-10-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737494635\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737484146\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/ColorSource-Spot/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=N0JzgjCdSgc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [339, 593, 672],\n    \"weight\": 7.7,\n    \"power\": 147,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"60 Lumileds LUXEON Rebel LED\",\n      \"lumens\": 6932\n    }\n  },\n  \"rdm\": {\n    \"modelId\": 518\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"33Hz\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5 Channel (Default)\",\n      \"shortName\": \"5ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Indigo\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"Direct\",\n      \"shortName\": \"dir\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Indigo\",\n        \"Lime\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"1 Channel\",\n      \"shortName\": \"1ch\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"rgb\",\n      \"rdmPersonalityIndex\": 4,\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Indigo\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/colorsource-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ColorSource Spot\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Joseph Gates\"],\n    \"createDate\": \"2019-10-21\",\n    \"lastModifyDate\": \"2019-10-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737494635\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737484146\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/ColorSource-Spot/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=N0JzgjCdSgc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [339, 593, 672],\n    \"weight\": 7.7,\n    \"power\": 147,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"60 Lumileds LUXEON Rebel LED\",\n      \"lumens\": 6932\n    }\n  },\n  \"rdm\": {\n    \"modelId\": 517\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"33Hz\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5 Channel (Default)\",\n      \"shortName\": \"5ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"Direct\",\n      \"shortName\": \"dir\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Lime\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"1 Channel\",\n      \"shortName\": \"1ch\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"rgb\",\n      \"rdmPersonalityIndex\": 4,\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/fos4PD16.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"fos/4 PD16\",\n  \"shortName\": \"fos/4 PD16\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-10-01\",\n    \"lastModifyDate\": \"2020-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501734\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501408\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/fos/4-Panels/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VTWd9qrpuW8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [406, 610, 631],\n    \"weight\": 25.4,\n    \"power\": 1070,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Deep Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Mint\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Dark Strobe\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Bright Strobe\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"Flicker\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [241, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent Red Shift\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear Red Shift\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [20, 249],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        }\n      ]\n    },\n    \"Mix\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Full Studio\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear interpolation from Studio to RGB\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full RGB\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [1, 165],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [166, 254],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6050K\",\n          \"colorTemperatureEnd\": \"10450K\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 10,\n          \"parameterEnd\": 0\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 0,\n          \"parameterEnd\": -10\n        }\n      ]\n    },\n    \"Tuning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Brightest\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Hybrid\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Spectral\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Intensity\",\n        \"Deep Red\",\n        \"Red\",\n        \"Mint\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Expanded\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Mix\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"3 Ch RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Intensity\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/fos4PD24.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"fos/4 PD24\",\n  \"shortName\": \"fos/4 PD24\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-10-01\",\n    \"lastModifyDate\": \"2020-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501734\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501408\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/fos/4-Panels/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VTWd9qrpuW8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [610, 610, 631],\n    \"weight\": 35.8,\n    \"power\": 1600,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Deep Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Mint\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Dark Strobe\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Bright Strobe\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"Flicker\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [241, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent Red Shift\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear Red Shift\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [20, 249],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        }\n      ]\n    },\n    \"Mix\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Full Studio\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear interpolation from Studio to RGB\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full RGB\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [1, 165],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [166, 254],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6050K\",\n          \"colorTemperatureEnd\": \"10450K\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 10,\n          \"parameterEnd\": 0\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 0,\n          \"parameterEnd\": -10\n        }\n      ]\n    },\n    \"Tuning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Brightest\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Hybrid\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Spectral\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Intensity\",\n        \"Deep Red\",\n        \"Red\",\n        \"Mint\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Expanded\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Mix\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"3 Ch RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Intensity\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/fos4PD8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"fos/4 PD8\",\n  \"shortName\": \"fos/4 PD8\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-10-01\",\n    \"lastModifyDate\": \"2020-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501734\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501408\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/fos/4-Panels/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VTWd9qrpuW8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [203, 610, 631],\n    \"weight\": 14.5,\n    \"power\": 540,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Deep Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Mint\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Dark Strobe\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Bright Strobe\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"Flicker\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [241, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent Red Shift\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear Red Shift\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [20, 249],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        }\n      ]\n    },\n    \"Mix\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Full Studio\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear interpolation from Studio to RGB\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full RGB\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [1, 165],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [166, 254],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6050K\",\n          \"colorTemperatureEnd\": \"10450K\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 10,\n          \"parameterEnd\": 0\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 0,\n          \"parameterEnd\": -10\n        }\n      ]\n    },\n    \"Tuning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Brightest\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Hybrid\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Spectral\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Intensity\",\n        \"Deep Red\",\n        \"Red\",\n        \"Mint\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Expanded\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Mix\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"3 Ch RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Intensity\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/fos4PL16.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"fos/4 PL16\",\n  \"shortName\": \"fos/4 PL16\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-10-01\",\n    \"lastModifyDate\": \"2020-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501734\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501408\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/fos/4-Panels/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VTWd9qrpuW8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [406, 610, 631],\n    \"weight\": 25.4,\n    \"power\": 1070,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Deep Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Dark Strobe\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Bright Strobe\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"Flicker\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [241, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent Red Shift\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear Red Shift\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [20, 249],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        }\n      ]\n    },\n    \"Mix\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Full Studio\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear interpolation from Studio to RGB\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full RGB\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [1, 165],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [166, 254],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6050K\",\n          \"colorTemperatureEnd\": \"10450K\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 10,\n          \"parameterEnd\": 0\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 0,\n          \"parameterEnd\": -10\n        }\n      ]\n    },\n    \"Tuning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Brightest\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Hybrid\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Spectral\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Intensity\",\n        \"Deep Red\",\n        \"Red\",\n        \"Amber\",\n        \"Lime\",\n        \"Green\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Expanded\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Mix\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"3 Ch RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Intensity\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/fos4PL24.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"fos/4 PL24\",\n  \"shortName\": \"fos/4 PL24\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-10-01\",\n    \"lastModifyDate\": \"2020-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501734\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501408\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/fos/4-Panels/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VTWd9qrpuW8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [610, 610, 631],\n    \"weight\": 35.8,\n    \"power\": 1600,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Deep Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Dark Strobe\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Bright Strobe\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"Flicker\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [241, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent Red Shift\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear Red Shift\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [20, 249],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        }\n      ]\n    },\n    \"Mix\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Full Studio\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear interpolation from Studio to RGB\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full RGB\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [1, 165],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [166, 254],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6050K\",\n          \"colorTemperatureEnd\": \"10450K\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 10,\n          \"parameterEnd\": 0\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 0,\n          \"parameterEnd\": -10\n        }\n      ]\n    },\n    \"Tuning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Brightest\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Hybrid\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Spectral\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Intensity\",\n        \"Deep Red\",\n        \"Red\",\n        \"Amber\",\n        \"Lime\",\n        \"Green\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Expanded\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Mix\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"3 Ch RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Intensity\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/fos4PL8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"fos/4 PL8\",\n  \"shortName\": \"fos/4 PL8\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2020-09-28\",\n    \"lastModifyDate\": \"2020-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501734\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501408\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/fos/4-Panels/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VTWd9qrpuW8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [203, 610, 631],\n    \"weight\": 14.5,\n    \"power\": 540,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Deep Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Dark Strobe\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Bright Strobe\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"Flicker\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [241, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent Red Shift\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear Red Shift\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [20, 249],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        }\n      ]\n    },\n    \"Mix\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Full Studio\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear interpolation from Studio to RGB\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full RGB\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [1, 165],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [166, 254],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6050K\",\n          \"colorTemperatureEnd\": \"10450K\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 10,\n          \"parameterEnd\": 0\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 0,\n          \"parameterEnd\": -10\n        }\n      ]\n    },\n    \"Tuning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Brightest\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Hybrid\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Spectral\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Intensity\",\n        \"Deep Red\",\n        \"Red\",\n        \"Amber\",\n        \"Lime\",\n        \"Green\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Expanded\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Mix\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"3 Ch RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Intensity\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/source-4wrd-color-ii.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Source 4WRD Color II\",\n  \"categories\": [\"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Randy Hall\"],\n    \"createDate\": \"2024-03-05\",\n    \"lastModifyDate\": \"2024-03-05\"\n  },\n  \"comment\": \"Retrofit for Source 4 fixtures; also can be paired with custom Source 4 Par(nel) fixtures\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/Products/Entertainment-Fixtures/S4WRD-C-II/Documentation.aspx#manuals\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Entertainment-Fixtures/S4WRD-C-II/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=olWwFKsCU-o\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 2051\n  },\n  \"physical\": {\n    \"dimensions\": [178, 142, 160],\n    \"weight\": 1.69,\n    \"power\": 150,\n    \"DMXconnector\": \"RJ45\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 6000\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"33Hz\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/source-four-led-series-2-daylight-hd.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Source Four LED Series 2 Daylight HD\",\n  \"shortName\": \"EtcSF2DaylightHD\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2019-07-11\",\n    \"lastModifyDate\": \"2020-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737483869\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501163\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/Source-Four-LED-Series-2/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=FXQDFq9jxI0\",\n      \"https://www.youtube.com/watch?v=oEjG8XLzuvs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [338, 615, 631],\n    \"weight\": 8.3,\n    \"power\": 248,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"60× 4-color Lumileds LUXEON® Rebel LED\",\n      \"lumens\": 13060\n    },\n    \"lens\": {\n      \"degreesMinMax\": [5, 90]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Mint\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Fan Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Color Point\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [2, 253],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2725K\",\n          \"colorTemperatureEnd\": \"6450K\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Red Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white\"\n        },\n        {\n          \"dmxRange\": [2, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus-green to neutral white\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white to full magenta\"\n        }\n      ]\n    },\n    \"Plus 7 Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Individual color adjust disabled\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Individual color adjust enabled\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Point\",\n        \"Tint\",\n        null,\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Red\",\n        \"Mint\",\n        \"Blue\",\n        \"Indigo\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSI\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSIC\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        \"Color Point\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"channels\": [\n        \"Red Emulated\",\n        \"Green Emulated\",\n        \"Blue Emulated\",\n        null,\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSI Plus 7\",\n      \"shortName\": \"HSI+7\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        null,\n        \"Mint\",\n        \"Blue\",\n        \"Indigo\",\n        null,\n        null\n      ]\n    },\n    {\n      \"name\": \"HSIC Plus 7\",\n      \"shortName\": \"HSIC+7\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        \"Color Point\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        null,\n        \"Mint\",\n        \"Blue\",\n        \"Indigo\",\n        null,\n        null\n      ]\n    },\n    {\n      \"name\": \"RGB Plus 7\",\n      \"shortName\": \"RGB+7\",\n      \"channels\": [\n        \"Red Emulated\",\n        \"Green Emulated\",\n        \"Blue Emulated\",\n        null,\n        \"Strobe\",\n        \"Fan Control\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        null,\n        \"Mint\",\n        \"Blue\",\n        \"Indigo\",\n        null,\n        null\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/source-four-led-series-2-lustr.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Source Four LED Series 2 Lustr\",\n  \"shortName\": \"EtcSF2Lustr\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jeppe Cohrt\", \"Dyami Caliri\"],\n    \"createDate\": \"2019-07-11\",\n    \"lastModifyDate\": \"2020-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737483869\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501163\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/Source-Four-LED-Series-2/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=oEjG8XLzuvs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [338, 615, 631],\n    \"weight\": 8.3,\n    \"power\": 171,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"60× 7-color Lumileds LUXEON® Rebel LED\",\n      \"lumens\": 8667\n    },\n    \"lens\": {\n      \"degreesMinMax\": [5, 90]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Fan Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Color Point\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [2, 253],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2725K\",\n          \"colorTemperatureEnd\": \"6450K\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Red Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white\"\n        },\n        {\n          \"dmxRange\": [2, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus-green to neutral white\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white to full magenta\"\n        }\n      ]\n    },\n    \"Plus 7 Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Individual color adjust disabled\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Individual color adjust enabled\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Red\",\n        \"Lime\",\n        \"Amber\",\n        \"Green\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSI\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSIC\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        \"Color Point\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"channels\": [\n        \"Red Emulated\",\n        \"Green Emulated\",\n        \"Blue Emulated\",\n        null,\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Point\",\n        \"Tint\",\n        null,\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSI Plus 7\",\n      \"shortName\": \"HSI+7\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        \"Lime\",\n        \"Amber\",\n        \"Green\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\"\n      ]\n    },\n    {\n      \"name\": \"HSIC Plus 7\",\n      \"shortName\": \"HSIC+7\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        \"Color Point\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        \"Lime\",\n        \"Amber\",\n        \"Green\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\"\n      ]\n    },\n    {\n      \"name\": \"RGB Plus 7\",\n      \"shortName\": \"RGB+7\",\n      \"channels\": [\n        \"Red Emulated\",\n        \"Green Emulated\",\n        \"Blue Emulated\",\n        null,\n        \"Strobe\",\n        \"Fan Control\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        \"Lime\",\n        \"Amber\",\n        \"Green\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/source-four-led-series-2-tungsten-hd.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Source Four LED Series 2 Tungsten HD\",\n  \"shortName\": \"EtcSF2TungstenHD\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2019-07-11\",\n    \"lastModifyDate\": \"2020-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737483869\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737501163\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/Source-Four-LED-Series-2/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=FXQDFq9jxI0\",\n      \"https://www.youtube.com/watch?v=oEjG8XLzuvs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [338, 615, 631],\n    \"weight\": 8.3,\n    \"power\": 208,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"60× 5-color Lumileds LUXEON® Rebel LED\",\n      \"lumens\": 11512\n    },\n    \"lens\": {\n      \"degreesMinMax\": [5, 90]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red Orange\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Mint\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Fan Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Color Point\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [2, 253],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2725K\",\n          \"colorTemperatureEnd\": \"6450K\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Red Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue Emulated\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white\"\n        },\n        {\n          \"dmxRange\": [2, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus-green to neutral white\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral white to full magenta\"\n        }\n      ]\n    },\n    \"Plus 7 Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Individual color adjust disabled\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Individual color adjust enabled\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Point\",\n        \"Tint\",\n        null,\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Red\",\n        \"Red Orange\",\n        \"Mint\",\n        \"Blue\",\n        \"Indigo\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSI\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSIC\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        \"Color Point\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"channels\": [\n        \"Red Emulated\",\n        \"Green Emulated\",\n        \"Blue Emulated\",\n        null,\n        \"Strobe\",\n        \"Fan Control\"\n      ]\n    },\n    {\n      \"name\": \"HSI Plus 7\",\n      \"shortName\": \"HSI+7\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        \"Red Orange\",\n        \"Mint\",\n        \"Blue\",\n        \"Indigo\",\n        null,\n        null\n      ]\n    },\n    {\n      \"name\": \"HSIC Plus 7\",\n      \"shortName\": \"HSIC+7\",\n      \"channels\": [\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Fan Control\",\n        \"Color Point\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        \"Red Orange\",\n        \"Mint\",\n        \"Blue\",\n        \"Indigo\",\n        null,\n        null\n      ]\n    },\n    {\n      \"name\": \"RGB Plus 7\",\n      \"shortName\": \"RGB+7\",\n      \"channels\": [\n        \"Red Emulated\",\n        \"Green Emulated\",\n        \"Blue Emulated\",\n        null,\n        \"Strobe\",\n        \"Fan Control\",\n        null,\n        \"Plus 7 Control\",\n        \"Red\",\n        null,\n        \"Mint\",\n        \"Blue\",\n        \"Indigo\",\n        null,\n        null\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/source-four-led-series-3-daylight-hdr.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Source Four LED Series 3 Daylight HDR\",\n  \"shortName\": \"EtcSF3DaylightHDR\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jeppe Cohrt\", \"Dyami Caliri\"],\n    \"createDate\": \"2022-05-07\",\n    \"lastModifyDate\": \"2022-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737510600\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737506242\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/Source-Four-LED-Series-3/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=OjdVerorbMs\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 1280\n  },\n  \"physical\": {\n    \"dimensions\": [216, 298, 700],\n    \"weight\": 8.9,\n    \"power\": 307,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"90 Lumileds LUXEON® C and CZ\",\n      \"lumens\": 10889\n    },\n    \"lens\": {\n      \"degreesMinMax\": [5, 90]\n    }\n  },\n  \"availableChannels\": {\n    \"Deep Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Mint\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Dark Strobe\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Bright Strobe\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"Flicker\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [241, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent Red Shift\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear Red Shift\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [20, 249],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        }\n      ]\n    },\n    \"Mix\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Full Studio\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear interpolation from Studio to RGB\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full RGB\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [1, 165],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [166, 254],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6050K\",\n          \"colorTemperatureEnd\": \"10450K\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 10,\n          \"parameterEnd\": 0\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 0,\n          \"parameterEnd\": -10\n        }\n      ]\n    },\n    \"Tuning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Brightest\"\n        },\n        {\n          \"dmxRange\": [50, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Spectral\"\n        },\n        {\n          \"dmxRange\": [150, 170],\n          \"type\": \"Generic\",\n          \"comment\": \"Metamer\"\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Intensity\",\n        \"Deep Red\",\n        \"Red\",\n        \"Mint\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Expanded\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Mix\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"3 Ch RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Intensity\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/etc/source-four-led-series-3-lustr-x8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Source Four LED Series 3 Lustr X8\",\n  \"shortName\": \"EtcSF3LustrX8\",\n  \"categories\": [\"Dimmer\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Jeppe Cohrt\", \"Dyami Caliri\"],\n    \"createDate\": \"2022-05-07\",\n    \"lastModifyDate\": \"2022-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737510600\",\n      \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737506242\"\n    ],\n    \"productPage\": [\n      \"https://www.etcconnect.com/Products/Lighting-Fixtures/Source-Four-LED-Series-3/Features.aspx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=OjdVerorbMs\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 1281\n  },\n  \"physical\": {\n    \"dimensions\": [216, 298, 700],\n    \"weight\": 8.9,\n    \"power\": 340,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"90 Lumileds LUXEON® C and CZ\",\n      \"lumens\": 14214\n    },\n    \"lens\": {\n      \"degreesMinMax\": [5, 90]\n    }\n  },\n  \"availableChannels\": {\n    \"Deep Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Lime\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Indigo\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Indigo\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Dark Strobe\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"40Hz\",\n          \"comment\": \"Bright Strobe\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Random\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"Flicker\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [241, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Incandescent Red Shift\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear Red Shift\"\n        },\n        {\n          \"dmxRange\": [40, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [20, 249],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        }\n      ]\n    },\n    \"Mix\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Full Studio\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear interpolation from Studio to RGB\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full RGB\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [1, 165],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [166, 254],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6050K\",\n          \"colorTemperatureEnd\": \"10450K\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 10,\n          \"parameterEnd\": 0\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tint\",\n          \"parameterStart\": 0,\n          \"parameterEnd\": -10\n        }\n      ]\n    },\n    \"Tuning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"Brightest\"\n        },\n        {\n          \"dmxRange\": [50, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"Spectral\"\n        },\n        {\n          \"dmxRange\": [150, 170],\n          \"type\": \"Generic\",\n          \"comment\": \"Metamer\"\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Direct\",\n      \"channels\": [\n        \"Intensity\",\n        \"Deep Red\",\n        \"Red\",\n        \"Amber\",\n        \"Lime\",\n        \"Green\",\n        \"Cyan\",\n        \"Blue\",\n        \"Indigo\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Expanded\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Mix\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"Studio\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\",\n        \"Tint\",\n        \"Tuning\",\n        \"Strobe\",\n        \"Dimmer Curve\",\n        \"Fan\"\n      ]\n    },\n    {\n      \"name\": \"3 Ch RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Intensity\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/edx-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"EDX-4\",\n  \"comment\": \"4-channel DMX dimmer pack, not sold anymore.\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Paul Rogalski\"],\n    \"createDate\": \"2024-10-02\",\n    \"lastModifyDate\": \"2024-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.yumpu.com/fr/document/view/29436703/4-channel-dmx-dimmer-pack\"\n    ],\n    \"productPage\": [\n      \"https://www.recordcase.de/en/eurolite-4-channel-dmx-dimmer-pack-edx-4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [320, 165, 110],\n    \"weight\": 3,\n    \"power\": 3680,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"off\",\n        \"brightnessEnd\": \"bright\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer Master\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer 1\",\n        \"Dimmer 2\",\n        \"Dimmer 3\",\n        \"Dimmer 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-7c-7-silent-slim.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED 7C-7 Silent Slim\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"spotlesscoder\", \"Re:Base\"],\n    \"createDate\": \"2024-11-11\",\n    \"lastModifyDate\": \"2024-11-11\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2024-11-11\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.13.1)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51915320-Manual-117485-1.000-eurolite-led-7c-7-silent-slim-spot-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51915320-eurolite-led-7c-7-silent-slim-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=tbf4f3Hc1M4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [220, 255, 110],\n    \"weight\": 2.4,\n    \"power\": 45,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Cold white\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cold White\"\n      }\n    },\n    \"Warm white\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Preset Colors\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold white\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Orange\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green yellow\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Salmon\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\"\n        }\n      ]\n    },\n    \"Internal Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 69],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Color temperature\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [50, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [90, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"4300K\"\n        },\n        {\n          \"dmxRange\": [130, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [170, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"8000K\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe Effect\",\n        \"Preset Colors\",\n        \"Internal Programs\",\n        \"Color temperature\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Cold white\",\n        \"Warm white\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Cold white\",\n        \"Warm white\",\n        \"Amber\",\n        \"UV\",\n        \"Master Dimmer\",\n        \"Strobe Effect\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe Effect\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Cold white\",\n        \"Warm white\",\n        \"Amber\",\n        \"UV\",\n        \"Preset Colors\",\n        \"Internal Programs\",\n        \"Color temperature\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-b-40.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED B-40\",\n  \"categories\": [\"Laser\", \"Flower\", \"Effect\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Charlélie Desmet\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-09-24\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"comment\": \"Laser Beam Effect\\nThree LED modules (RGBW), a red laser and a green laser are contained in a rotating sphere with lenses.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51741087-Manual-138662-1.300-eurolite-led-b-40-laser-beam-effect-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51741087-eurolite-led-b-40-laser-beam-effect.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_AniHjqqb_0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [310, 310, 390],\n    \"weight\": 4,\n    \"power\": 65,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5× 8W QCL RGBW LEDs, red laser (650nm, 95.88mW), green laser (532nm, 39.44mW)\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"LED Group 1\", \"LED Group 2\", \"LED Group 3\", \"Red Laser\", \"Green Laser\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"LED\": [\"LED Group 1\", \"LED Group 2\", \"LED Group 3\"],\n      \"Laser\": [\"Red Laser\", \"Green Laser\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / Red / Red\",\n          \"colors\": [\"#ff0000\", \"#ff0000\", \"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [16, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green / Green / Green\",\n          \"colors\": [\"#00ff00\", \"#00ff00\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [27, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue / Blue / Blue\",\n          \"colors\": [\"#0000ff\", \"#0000ff\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [38, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White / White / White\",\n          \"colors\": [\"#ffffff\", \"#ffffff\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [49, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / Green / Blue\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [60, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / Green / White\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [71, 81],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / Blue / White\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [82, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green / Blue / White\",\n          \"colors\": [\"#00ff00\", \"#0000ff\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [93, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow / Pink / Light Red\",\n          \"colors\": [\"#ffff00\", \"#ff00ff\", \"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [104, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow / Cyan / Light Green\",\n          \"colors\": [\"#ffff00\", \"#00ffff\", \"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [115, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink / Cyan / Light Blue\",\n          \"colors\": [\"#ff00ff\", \"#00ffff\", \"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [126, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red / Light Green / Light Blue\",\n          \"colors\": [\"#ff8080\", \"#80ff80\", \"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [137, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow / Yellow / Yellow\",\n          \"colors\": [\"#ffff00\", \"#ffff00\", \"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [148, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink / Pink / Pink\",\n          \"colors\": [\"#ff00ff\", \"#ff00ff\", \"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [159, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red / Light Red / Light Red\",\n          \"colors\": [\"#ff8080\", \"#ff8080\", \"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [170, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan / Cyan / Cyan\",\n          \"colors\": [\"#00ffff\", \"#00ffff\", \"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [181, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green / Light Green / Light Green\",\n          \"colors\": [\"#80ff80\", \"#80ff80\", \"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [192, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue / Light Blue / Light Blue\",\n          \"colors\": [\"#8080ff\", \"#8080ff\", \"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [203, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White / White / White\",\n          \"colors\": [\"#ffffff\", \"#ffffff\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [214, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Yellow / Light Yellow / Light Yellow\",\n          \"colors\": [\"#ffff80\", \"#ffff80\", \"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [225, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Cyan / Light Cyan / Light Cyan\",\n          \"colors\": [\"#80ffff\", \"#80ffff\", \"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [236, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White / Light Cyan / Light Yellow\",\n          \"colors\": [\"#ffffff\", \"#80ffff\", \"#ffff80\"]\n        },\n        {\n          \"dmxRange\": [247, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full White / Full White / Full White\",\n          \"colors\": [\"#ffffff\", \"#ffffff\", \"#ffffff\"]\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Laser\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Laser Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [47, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Laser Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [88, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Laser Red + Green\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [129, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Laser Red Strobe + Green\",\n          \"colors\": [\"#800000\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [170, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Laser Red + Green Strobe\",\n          \"colors\": [\"#ff0000\", \"#008000\"]\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Laser Red + Green Strobe alternating\",\n          \"colors\": [\"#800000\", \"#008000\"]\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [41, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [77, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [113, 148],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [149, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [185, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        }\n      ]\n    },\n    \"Auto Programs Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 250],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Auto Programs\",\n        \"Auto Programs Speed\",\n        \"Rotation\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"LED Red\",\n        \"LED Green\",\n        \"LED Blue\",\n        \"LED White\",\n        \"Color Presets\",\n        \"Master Dimmer\",\n        \"LED Strobe\",\n        \"Laser\",\n        \"Laser Strobe\",\n        \"Rotation\"\n      ]\n    },\n    {\n      \"name\": \"22 Channel\",\n      \"shortName\": \"22ch\",\n      \"channels\": [\n        \"LED Group 1 Red\",\n        \"LED Group 1 Green\",\n        \"LED Group 1 Blue\",\n        \"LED Group 1 White\",\n        \"LED Group 1 Strobe\",\n        \"LED Group 2 Red\",\n        \"LED Group 2 Green\",\n        \"LED Group 2 Blue\",\n        \"LED Group 2 White\",\n        \"LED Group 2 Strobe\",\n        \"LED Group 3 Red\",\n        \"LED Group 3 Green\",\n        \"LED Group 3 Blue\",\n        \"LED Group 3 White\",\n        \"LED Group 3 Strobe\",\n        \"Color Presets\",\n        \"Master Dimmer\",\n        \"Laser\",\n        \"Laser Strobe\",\n        \"Auto Programs\",\n        \"Auto Programs Speed\",\n        \"Rotation\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-bar-12-qcl-rgba-bar.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Bar-12 QCL RGBA Bar\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Rainer Jung\"],\n    \"createDate\": \"2022-05-22\",\n    \"lastModifyDate\": \"2022-05-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51930396-Manual-120587-1.200-eurolite-led-bar-12-qcl-rgba-bar-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51930396-eurolite-led-bar-12-qcl-rgba-bar.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ZIj0aZyng1Q\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1090, 65, 100],\n    \"weight\": 2.9,\n    \"power\": 24,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Auto Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 119],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [120, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Orange\",\n          \"colors\": [\"#be6500\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Yellow\",\n          \"colors\": [\"#8cff00\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Salmon\",\n          \"colors\": [\"#ff8c8c\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#8cffff\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#8cff8c\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8c00\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#ccbfff\"]\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#8c8cff\"]\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\",\n          \"colors\": [\"#00008c\"]\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff008c\"]\n        }\n      ]\n    },\n    \"Strobe / Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [50, 69],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4900K\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7500K\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Auto Program\",\n        \"Auto Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Presets\",\n        \"Strobe\",\n        \"Auto Program\",\n        \"Auto Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe / Program\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Color Temperature\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Auto Program\",\n        \"Auto Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-bar-3-hcl-bar.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Bar-3 HCL Bar\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Rainer Jung\"],\n    \"createDate\": \"2020-01-14\",\n    \"lastModifyDate\": \"2022-05-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51930395-Manual-110557-1.000-eurolite-led-bar-3-hcl-bar-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51930395-eurolite-led-bar-3-hcl-bar.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=SV2AFTdJKNE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [265, 129, 87],\n    \"weight\": 0.9,\n    \"power\": 12,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 69],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Orange\",\n          \"colors\": [\"#be6500\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Yellow\",\n          \"colors\": [\"#8cff00\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Salmon\",\n          \"colors\": [\"#ff8c8c\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#8cffff\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#8cff8c\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8c00\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#ccbfff\"]\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#8c8cff\"]\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\",\n          \"colors\": [\"#00008c\"]\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff008c\"]\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Presets\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Presets\",\n        \"Mode\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Presets\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-bar-6-qcl-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Bar-6 QCL RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Luke Nelson\"],\n    \"createDate\": \"2022-10-12\",\n    \"lastModifyDate\": \"2024-11-23\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2022-10-12\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.6)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51930399-Manual-120629-1.100-eurolite-led-bar-6-qcl-rgbw-bar-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51930399-eurolite-led-bar-6-qcl-rgbw-bar.html\"\n    ],\n    \"video\": [\"https://www.youtube.com/watch?v=tXEgjiP5YWA\"]\n  },\n  \"physical\": {\n    \"dimensions\": [585, 65, 100],\n    \"weight\": 2.9,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Auto Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode\"\n        },\n        {\n          \"dmxRange\": [120, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Auto Program Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green yellow\",\n          \"colors\": [\"#d4fb79\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00fdff\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff40ff\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#fffb00\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#00fdff\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff40ff\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff9300\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#73fa79\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff40ff\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#8cff8c\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#73fa79\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#76d6ff\"]\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#fff8af\"]\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#d783ff\"]\n        }\n      ]\n    },\n    \"Strobe / Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [50, 69],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4900K\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7500K\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\"Auto Program\", \"Auto Program Speed\"]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\"Red\", \"Green\", \"Blue\", \"White\"]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Presets\",\n        \"Strobe\",\n        \"Auto Program\",\n        \"Auto Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe / Program\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Temperature\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Auto Program\",\n        \"Auto Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-big-party-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Big PARty Spot\",\n  \"shortName\": \"EuroliteBigPARtySpot\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-04-07\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/42110195-Manual-126303-1.100-eurolite-led-big-party-spot-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn42110195-eurolite-led-big-party-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=O6SUj9P8Yaw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 245, 130],\n    \"weight\": 1.1,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"54x 1W LEDs (12x red, 18x green, 18x blue, 6x white)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Effects\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-big-party-tcl-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Big PARty TCL Spot\",\n  \"shortName\": \"EuroliteBigPARtyTCLSpot\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-04-07\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/42110196-Manual-126305-1.100-eurolite-led-big-party-tcl-spot-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn42110196-eurolite-led-big-party-tcl-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2zlm7RiVOKY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [150, 245, 255],\n    \"weight\": 1,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"54x 3W TCL RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-Channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Effects\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-dmx-pixel-tube-16-rgb-ip20.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED DMX Pixel Tube 16 RGB IP20\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"LordVonAdel\"],\n    \"createDate\": \"2022-10-25\",\n    \"lastModifyDate\": \"2022-10-25\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51928602-Manual-85739-1.100-eurolite-led-dmx-pixel-tube-16-rgb-ip20-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51928602-eurolite-led-dmx-pixel-tube-16-rgb-ip20.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=7QjVn5cwiVg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1005, 50, 75],\n    \"weight\": 1.35,\n    \"power\": 38,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [16, 1, 1]\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"highlightValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"highlightValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"highlightValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"48-channel\",\n      \"shortName\": \"48ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-fe-1500.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED FE-1500\",\n  \"shortName\": \"ELFE1500\",\n  \"categories\": [\"Flower\", \"Laser\", \"Strobe\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-12-31\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51741080-Manual-89092-1.000-eurolite-led-fe-1500-hybrid-laser-flower-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51741080-eurolite-led-fe-1500-hybrid-laser-flower.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=3bB3ZE9Rm-o\",\n      \"https://www.youtube.com/watch?v=anZ5xqb2MEY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [313, 315, 246],\n    \"weight\": 4.2,\n    \"power\": 40,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 3W RGBWA, 8x 1W white, red & green laser\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"availableChannels\": {\n    \"Operating Mode\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [10, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aut0: Laser + RGBWA LEDs + white LEDs\"\n        },\n        {\n          \"dmxRange\": [25, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aut1: Laser + RGBWA LEDs\"\n        },\n        {\n          \"dmxRange\": [40, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aut2: Laser + white LEDs\"\n        },\n        {\n          \"dmxRange\": [55, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aut3: RGBWA LEDs + white LEDs\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aut4: RGBWA LEDs\"\n        },\n        {\n          \"dmxRange\": [85, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aut5: Laser\"\n        },\n        {\n          \"dmxRange\": [100, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aut6: white LEDs\"\n        },\n        {\n          \"dmxRange\": [115, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sou0: Laser + RGBWA LEDs + white LEDs\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sou1: Laser + RGBWA LEDs\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [145, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sou2: Laser + white LEDs\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sou3: RGBWA LEDs + white LEDs\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [175, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sou4: RGBWA LEDs\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sou5: Laser\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [205, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sou6: white LEDs\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"DMX mode\"\n        }\n      ]\n    },\n    \"RGBWA LEDs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#ff0000\"],\n          \"comment\": \"White + red\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + green\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + blue\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"Blue + amber\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Amber + white\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#00ff00\"],\n          \"comment\": \"White + green\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ffbf00\"],\n          \"comment\": \"Green + amber\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ff0000\"],\n          \"comment\": \"Amber + red\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + blue\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Blue + white\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + green + blue\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffbf00\"],\n          \"comment\": \"Red + green + amber\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Red + green + white\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffbf00\", \"#0000ff\"],\n          \"comment\": \"Red + amber + blue\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffffff\", \"#0000ff\"],\n          \"comment\": \"Red + white + blue\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Red + amber + white\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Amber + green + blue\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Blue + green + white\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Amber + green + white\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ffffff\", \"#0000ff\"],\n          \"comment\": \"Amber + white + blue\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"Red + green + blue + amber\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + green + blue + white\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#00ff00\", \"#ffffff\", \"#ffbf00\"],\n          \"comment\": \"Blue + green + white + amber\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Red + green + amber + white\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#ff0000\", \"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"White + red + blue + amber\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Red + green + blue + amber + white\"\n        },\n        {\n          \"dmxRange\": [165, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic color change (one color)\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic color change (two colors)\"\n        }\n      ]\n    },\n    \"Color Change Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"RGBWA LED Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"White LED Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Light pattern 10\"\n        },\n        {\n          \"dmxRange\": [110, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Laser\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red on\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [50, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green on\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [90, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Change green and red\",\n          \"colors\": [\"#00ff00\", \"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [130, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red on + Green strobe\",\n          \"colors\": [\"#ff0000\", \"#00aa00\"]\n        },\n        {\n          \"dmxRange\": [170, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green on + Red strobe\",\n          \"colors\": [\"#00ff00\", \"#aa0000\"]\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red strobe + Green strobe\",\n          \"colors\": [\"#aa0000\", \"#00aa00\"]\n        }\n      ]\n    },\n    \"Laser Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No strobe\"\n        },\n        {\n          \"dmxRange\": [5, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"RGBWA LED rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [5, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Laser rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [5, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Operating Mode\",\n        \"RGBWA LEDs\",\n        \"Color Change Speed\",\n        \"RGBWA LED Strobe\",\n        \"White LED Strobe\",\n        \"Laser\",\n        \"Laser Strobe\",\n        \"RGBWA LED rotation\",\n        \"Laser rotation\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-h2o.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED H2O\",\n  \"shortName\": \"ELH2O\",\n  \"categories\": [\"Effect\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-11-08\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"comment\": \"Don't confuse this fixture with the Eurolite LED H2O TCL, which is only controllable with an IR remote.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51918700-Manual-137293-1.400-eurolite-led-h2o-water-effect-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51918700-eurolite-led-h2o-water-effect.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=idoxSYB6oHk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [165, 170, 135],\n    \"weight\": 0.8,\n    \"power\": 26,\n    \"DMXconnector\": \"3.5mm stereo jack\",\n    \"bulb\": {\n      \"type\": \"9W TCL LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [35, 35]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Shutter\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-kls-801.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED KLS-801\",\n  \"shortName\": \"KLS801\",\n  \"categories\": [\"Stand\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-01-20\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/42109851-Manual-60662-1.200-eurolite-led-kls-801-compact-light-set-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn42109851-eurolite-led-kls-801-compact-light-set.html\"\n    ],\n    \"video\": [\"https://www.youtube.com/watch?v=QjuPg9DT9Ok\"]\n  },\n  \"physical\": {\n    \"dimensions\": [1200, 315, 65],\n    \"weight\": 9,\n    \"power\": 130,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"4\", \"3\", \"2\", \"1\"]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"Preset programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Red 1\",\n            \"Green 1 / Fade Time\": \"Green 1\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [230, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic mode\",\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Red 1 / Running Speed\": \"Running Speed\",\n            \"Green 1 / Fade Time\": \"Fade Time\"\n          }\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Running Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Fade Time\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"short\",\n        \"durationEnd\": \"long\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Preset programs\",\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red 1 / Running Speed\",\n        \"Green 1 / Fade Time\",\n        \"Blue 1\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"2\", \"3\", \"4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-ml-56-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED ML-56 RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Nominari UG\"],\n    \"createDate\": \"2019-01-15\",\n    \"lastModifyDate\": \"2019-01-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51913667-Anleitung-56894-1.00-eurolite-led-ml-56-rgbw-36x3w-sil-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51913667-eurolite-led-ml-56-rgbw-36x3w-sil.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=gEsY_2H1XfI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [240, 300, 310],\n    \"weight\": 5,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"36× 3W RGBW LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Cool White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Controlled (15 Colors)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Cool White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Cool White\",\n        \"Dimmer\",\n        \"Function\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-par-56-tcl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR-56 TCL\",\n  \"shortName\": \"PAR56\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-05-24\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51913611-MANUAL-1.00-de-en_00066247.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51913611-eurolite-led-par-56-tcl-9x3w-short-black.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wS_oUSBZGgM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [165, 205, 215],\n    \"weight\": 1.5,\n    \"power\": 45,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14, 14]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"highlightValue\": 220,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Shutter\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-party-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PARty Spot\",\n  \"shortName\": \"EurolitePARtySpot\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-04-07\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/42110192-Manual-126227-2.000-eurolite-led-party-spot-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn42110192-eurolite-led-party-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=fJKxgmbVv4A\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [145, 155, 90],\n    \"weight\": 0.46,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 1W LEDs (3x red, 3x green, 3x blue, 3x white)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Effects\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-party-tcl-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PARty TCL Spot\",\n  \"shortName\": \"EurolitePARtyTCLSpot\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Adrian Branchadell\", \"Felix Edelmann\"],\n    \"createDate\": \"2019-04-07\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/42110193-Manual-138613-2.100-eurolite-led-party-tcl-spot-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn42110193-eurolite-led-party-tcl-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=lrAatXEygvI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [150, 160, 90],\n    \"weight\": 0.46,\n    \"power\": 10,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 3W TCL RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-Channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Effects\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-pix-12-hcl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PIX-12 HCL\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Nominari UG\", \"JonahKr\"],\n    \"createDate\": \"2019-01-15\",\n    \"lastModifyDate\": \"2021-09-13\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51930406-Manual-107249-1.00-eurolite-led-pix-12-hcl-bar-en_de.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51930406-eurolite-led-pix-12-hcl-bar.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=La8oyulvtJ4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1000, 165, 115],\n    \"weight\": 5,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin\",\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    },\n    \"bulb\": {\n      \"type\": \"12× 10W HCL LED (RGBAWUV)\"\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1+2\": [\"1\", \"2\"],\n      \"3+4\": [\"3\", \"4\"],\n      \"5+6\": [\"5\", \"6\"],\n      \"7+8\": [\"7\", \"8\"],\n      \"9+10\": [\"9\", \"10\"],\n      \"11+12\": [\"11\", \"12\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pixel Combinations\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 15],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3\"\n        },\n        {\n          \"dmxRange\": [16, 21],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 2+3+4\"\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 3+4+5\"\n        },\n        {\n          \"dmxRange\": [28, 33],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 4+5+6\"\n        },\n        {\n          \"dmxRange\": [34, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 5+6+7\"\n        },\n        {\n          \"dmxRange\": [40, 45],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 6+7+8\"\n        },\n        {\n          \"dmxRange\": [46, 51],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 7+8+9\"\n        },\n        {\n          \"dmxRange\": [52, 57],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 8+9+10\"\n        },\n        {\n          \"dmxRange\": [58, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 9+10+11\"\n        },\n        {\n          \"dmxRange\": [64, 69],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 10+11+12\"\n        },\n        {\n          \"dmxRange\": [70, 75],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+11+12\"\n        },\n        {\n          \"dmxRange\": [76, 81],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+12\"\n        },\n        {\n          \"dmxRange\": [82, 87],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1\"\n        },\n        {\n          \"dmxRange\": [88, 93],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2\"\n        },\n        {\n          \"dmxRange\": [94, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3\"\n        },\n        {\n          \"dmxRange\": [100, 105],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4\"\n        },\n        {\n          \"dmxRange\": [106, 111],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4+5\"\n        },\n        {\n          \"dmxRange\": [112, 117],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4+5+6\"\n        },\n        {\n          \"dmxRange\": [118, 123],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4+5+6+7\"\n        },\n        {\n          \"dmxRange\": [124, 129],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4+5+6+7+8\"\n        },\n        {\n          \"dmxRange\": [130, 135],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4+5+6+7+8+9\"\n        },\n        {\n          \"dmxRange\": [136, 141],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4+5+6+7+8+9+10\"\n        },\n        {\n          \"dmxRange\": [142, 147],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4+5+6+7+8+9+10+11\"\n        },\n        {\n          \"dmxRange\": [148, 153],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 1+2+3+4+5+6+7+8+9+10+11+12\"\n        },\n        {\n          \"dmxRange\": [154, 159],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 12\"\n        },\n        {\n          \"dmxRange\": [160, 165],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 11+12\"\n        },\n        {\n          \"dmxRange\": [166, 171],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 10+11+12\"\n        },\n        {\n          \"dmxRange\": [172, 177],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 9+10+11+12\"\n        },\n        {\n          \"dmxRange\": [178, 183],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 8+9+10+11+12\"\n        },\n        {\n          \"dmxRange\": [184, 189],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 7+8+9+10+11+12\"\n        },\n        {\n          \"dmxRange\": [190, 195],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 6+7+8+9+10+11+12\"\n        },\n        {\n          \"dmxRange\": [196, 201],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 5+6+7+8+9+10+11\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 4+5+6+7+8+9+10+11\"\n        },\n        {\n          \"dmxRange\": [208, 213],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 3+4+5+6+7+8+9+10+11\"\n        },\n        {\n          \"dmxRange\": [214, 219],\n          \"type\": \"Generic\",\n          \"comment\": \"Pixel 2+3+4+5+6+7+8+9+10+11\"\n        },\n        {\n          \"dmxRange\": [220, 225],\n          \"type\": \"Generic\",\n          \"comment\": \"All Pixels on\"\n        },\n        {\n          \"dmxRange\": [226, 231],\n          \"type\": \"Generic\",\n          \"comment\": \"Odd Pixels on\"\n        },\n        {\n          \"dmxRange\": [232, 237],\n          \"type\": \"Generic\",\n          \"comment\": \"Even Pixels on\"\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"All Pixel On\"\n        }\n      ]\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [50, 69],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4900K\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7500K\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Color Presets $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green aka Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue aka Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + White\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Amber\",\n          \"colors\": [\"#ff6000\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + UV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue aka Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + White\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Amber\",\n          \"colors\": [\"#80df00\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + UV\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue aka White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + White\",\n          \"colors\": [\"#80ffff\"]\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + White + Amber\",\n          \"colors\": [\"#bf9f80\"]\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White + Amber + UV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber + Red + UV\",\n          \"colors\": [\"#ff6060\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue + White + UV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White + UV\",\n          \"colors\": [\"#ffff80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White + Amber\",\n          \"colors\": [\"#ffdf40\"]\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + Amber + UV\",\n          \"colors\": [\"#80df80\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White + Amber + UV\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"]\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Presets Master\",\n        \"Pixel Combinations\",\n        \"Function\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        \"UV Master\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Color Presets $pixelKey\"\n          ]\n        },\n        \"Color Temperature\",\n        \"Function\"\n      ]\n    },\n    {\n      \"name\": \"36-channel\",\n      \"shortName\": \"36ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"1+2\",\n            \"3+4\",\n            \"5+6\",\n            \"7+8\",\n            \"9+10\",\n            \"11+12\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\",\n            \"UV $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"74-channel\",\n      \"shortName\": \"74ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\",\n            \"UV $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-pix-144.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PIX-144\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Paolo Zanchi\"],\n    \"createDate\": \"2019-02-06\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51930439-Manual-143047-1.200-eurolite-led-pix-144-rgb-bar-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51930439-eurolite-led-pix-144-rgb-bar.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=O0GaXoeFQaQ\",\n      \"https://www.youtube.com/watch?v=uWRSK040pnI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1020, 65, 80],\n    \"weight\": 1,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"144x RGB-SMD LEDs\"\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [125, 65, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [8, 1, 1],\n    \"pixelGroups\": {\n      \"1/2\": [\"1\", \"2\", \"3\", \"4\"],\n      \"2/2\": [\"5\", \"6\", \"7\", \"8\"],\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Auto Program / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-control 7-color\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Auto Program $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB program\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Dimmer Master\",\n        \"Auto Program / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Auto Program Master\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Strobe $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Auto Program $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"24-channel\",\n      \"shortName\": \"24ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"48-channel\",\n      \"shortName\": \"48ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\",\n            \"Strobe $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Auto Program $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-ps-4-hcl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PS-4 HCL\",\n  \"shortName\": \"LEDPS4\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-05-24\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/download_t/51913503-MANUAL-1.10-de-en_00096357.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51913503-eurolite-led-ps-4-hcl-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=m-E_xYKWuCY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [188.5, 195.5, 117],\n    \"weight\": 1.5,\n    \"power\": 33,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12 W LED RGBAWUV\"\n    }\n  },\n  \"availableChannels\": {\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8800ff\"],\n          \"comment\": \"UV\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8080\"],\n          \"comment\": \"Red + White\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6000\"],\n          \"comment\": \"Red + Amber\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"],\n          \"comment\": \"Red + UV\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ff80\"],\n          \"comment\": \"Green + White\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#92ff00\"],\n          \"comment\": \"Green + Amber\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#8800ff\"],\n          \"comment\": \"Green + UV\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8080ff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbfff\"],\n          \"comment\": \"Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#8800ff\"],\n          \"comment\": \"Blue + UV\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf80\"],\n          \"comment\": \"White + Amber\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#8800ff\"],\n          \"comment\": \"White + UV\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#8800ff\"],\n          \"comment\": \"Amber + UV\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6080\"],\n          \"comment\": \"Red + Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ff80\", \"#8800ff\"],\n          \"comment\": \"Green + White + UV\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdf80\", \"#8800ff\"],\n          \"comment\": \"All\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"defaultValue\": 128,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4 channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Color Presets\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"10 channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-sls-12-bcl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED SLS-12 BCL\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2020-09-20\",\n    \"lastModifyDate\": \"2020-09-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51915395-Manual-80943-1.300-eurolite-led-sls-12-bcl-12x5w-floor-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51915395-eurolite-led-sls-12-bcl-12x5w-floor.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=cwewR_yjDso\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 310, 110],\n    \"weight\": 3.5,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 5W BCL LED (White+Amber)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [23, 23]\n    }\n  },\n  \"availableChannels\": {\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Sound / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 28],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [29, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [58, 82],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"],\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [83, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 1\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [88, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 2\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [93, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 3\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [98, 163],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Which mode is selected in this DMX range?\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [164, 168],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [169, 245],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Which mode is selected in this DMX range?\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"White\",\n        \"Amber\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"White\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Sound / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"White\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe / Speed / Sensitivity\",\n        \"Effect\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-sls-5-bcl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED SLS-5 BCL\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Christian Hollbjär\", \"darth62\"],\n    \"createDate\": \"2020-09-20\",\n    \"lastModifyDate\": \"2020-09-20\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2020-04-17\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.10.5 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51915390-Manual-80943-1.300-eurolite-led-sls-5-bcl-5x5w-floor-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51915390-eurolite-led-sls-5-bcl-5x5w-floor.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [230, 270, 110],\n    \"weight\": 3,\n    \"power\": 24,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5× 5W BCL LED (White+Amber)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"availableChannels\": {\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Sound / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 28],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [29, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [58, 82],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"],\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [83, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 1\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [88, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 2\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [93, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dreaming 3\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [98, 163],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Which mode is selected in this DMX range?\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [164, 168],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [169, 245],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Which mode is selected in this DMX range?\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Speed / Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"White\",\n        \"Amber\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"White\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Sound / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"White\",\n        \"Amber\",\n        \"Dimmer\",\n        \"Strobe / Speed / Sensitivity\",\n        \"Effect\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-sls-6-uv-floor.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED SLS-6 UV Floor\",\n  \"shortName\": \"LEDSLS6UV\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-05-24\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/download_t/51915282-MANUAL-1.10-en-de_00102317.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51915282-eurolite-led-sls-6-uv-floor.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [230, 230, 110],\n    \"weight\": 1,\n    \"power\": 20,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2 channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"UV\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"4 channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"UV\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-svf-1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED SVF-1\",\n  \"shortName\": \"SVF1\",\n  \"categories\": [\"Flower\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-08-01\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51918662-MANUAL-1.10-de-en_00073902.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/download/51918662-Manual-73902-1.100-eurolite-led-svf-1-flower-effect-de_en.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=fg8kl3vCfD4\",\n      \"https://www.youtube.com/watch?v=DyPYm84KdFQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [580, 325, 625],\n    \"weight\": 6,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED 5mm\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [13, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [26, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [39, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [52, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [65, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [78, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [91, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [104, 116],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [117, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [130, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [143, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [156, 168],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [169, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [182, 194],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [195, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"All programs looping\"\n        },\n        {\n          \"dmxRange\": [215, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"defaultValue\": 132,\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"All LEDs off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-Channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tha-100f-mk2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED THA-100F MK2\",\n  \"shortName\": \"EuroliteTHA100F-2\",\n  \"categories\": [\"Dimmer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-04-15\",\n    \"lastModifyDate\": \"2019-04-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/41602126-Manual-106094-1.00-eurolite-led-tha-100f-mk2-theater-spot-en_de.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn41602126-eurolite-led-tha-100f-mk2-theater-spot.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [265, 335, 370],\n    \"weight\": 6,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"COB warm white 100W LED\",\n      \"colorTemperature\": 3200\n    },\n    \"lens\": {\n      \"degreesMinMax\": [6, 31]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Control Board setting\"\n        },\n        {\n          \"dmxRange\": [16, 45],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear (halogen)\"\n        },\n        {\n          \"dmxRange\": [46, 75],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square (halogen)\"\n        },\n        {\n          \"dmxRange\": [76, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse (halogen)\"\n        },\n        {\n          \"dmxRange\": [106, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-shaped (halogen)\"\n        },\n        {\n          \"dmxRange\": [136, 165],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear (LED)\"\n        },\n        {\n          \"dmxRange\": [166, 195],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square (LED)\"\n        },\n        {\n          \"dmxRange\": [196, 225],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse (LED)\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-shaped (LED)\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tha-100f.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED THA-100F\",\n  \"shortName\": \"EuroliteTHA100F\",\n  \"categories\": [\"Dimmer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"RAZAKANIRINA\"],\n    \"createDate\": \"2019-04-15\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/41602125-Manual-136231-1.200-eurolite-led-tha-100f-theatre-spot-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn41602125-eurolite-led-tha-100f-theatre-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=EByMlz4lq94\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [305.0, 369.5, 387.3],\n    \"weight\": 5.5,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"COB warm white 100W LED\",\n      \"colorTemperature\": 3200\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 50]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Control Board setting\"\n        },\n        {\n          \"dmxRange\": [16, 45],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear (halogen)\"\n        },\n        {\n          \"dmxRange\": [46, 75],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square (halogen)\"\n        },\n        {\n          \"dmxRange\": [76, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse (halogen)\"\n        },\n        {\n          \"dmxRange\": [106, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-shaped (halogen)\"\n        },\n        {\n          \"dmxRange\": [136, 165],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear (LED)\"\n        },\n        {\n          \"dmxRange\": [166, 195],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square (LED)\"\n        },\n        {\n          \"dmxRange\": [196, 225],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse (LED)\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-shaped (LED)\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-theatre-cob-200-rgb-ww.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Theatre COB 200 RGB+WW\",\n  \"shortName\": \"LED THA COB 200\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Benjamin Blaikner / Theater der Mitte\"],\n    \"createDate\": \"2024-11-25\",\n    \"lastModifyDate\": \"2024-11-25\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.at/download/41602038-Anleitung-131953-1.000-eurolite-led-theatre-cob-200-rgb+ww-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.at/de/mpn41602038-eurolite-led-theatre-cob-200-rgb+ww.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [260, 380, 200],\n    \"weight\": 4.11,\n    \"power\": 140,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1 x COB (Chip-on-board) 4in1 QCL RGB/WW\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 35]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Warm White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Orange\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green yellow\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Salmon\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light green\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark blue\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full on\"\n        }\n      ]\n    },\n    \"Internal Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [180, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control program 9\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe 2\": {\n      \"name\": \"Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music-controlled program\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 39],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1800K\"\n        },\n        {\n          \"dmxRange\": [40, 69],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2200K\"\n        },\n        {\n          \"dmxRange\": [70, 99],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [100, 129],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [130, 159],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4300K\"\n        },\n        {\n          \"dmxRange\": [160, 189],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [190, 219],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Warm White\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Color Presets\",\n        \"Internal Programs\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Warm White\",\n        \"Master Dimmer\",\n        \"Strobe 2\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Warm White\",\n        \"Color Presets\",\n        \"Internal Programs\",\n        \"Program Speed\",\n        \"Color Temperature\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tl-3-rgb-uv.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TL-3 RGB+UV\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Barnaby Collins\"],\n    \"createDate\": \"2022-06-09\",\n    \"lastModifyDate\": \"2022-06-09\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2022-05-29\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.4)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51915445-Manual-128720-1.100-eurolite-led-tl-3-rgb+uv-trusslight-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51915445-eurolite-led-tl-3-rgb+uv-trusslight.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=0MoC10E_w90\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [122, 108, 117],\n    \"weight\": 0.89,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3× 7W RGB+UV 4in1 LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Preset Colours\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark orange\",\n          \"colors\": [\"#f07b27\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green yellow\",\n          \"colors\": [\"#88ff00\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Salmon\",\n          \"colors\": [\"#ff8888\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#00cccc\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light green\",\n          \"colors\": [\"#88ff88\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#cfb5e2\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\",\n          \"colors\": [\"#88ffff\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark blue\",\n          \"colors\": [\"#000088\"]\n        },\n        {\n          \"dmxRange\": [170, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff88ff\"]\n        }\n      ]\n    },\n    \"Auto mode / Sound control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 69],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel 1\",\n      \"shortName\": \"4-1c\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Preset Colours\",\n        \"Auto mode / Sound control\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Preset Colours\",\n        \"Auto mode / Sound control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tl-4-qcl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TL-4 QCL\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Clemens Mair\"],\n    \"createDate\": \"2021-10-29\",\n    \"lastModifyDate\": \"2021-10-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51915448-Manual-122742-1.000-eurolite-led-tl-4-qcl-rgb+uv-trusslight-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51915448-eurolite-led-tl-4-qcl-rgb+uv-trusslight.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=FZe4SH3rlaQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [145, 130, 155],\n    \"weight\": 1.3,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4× 8W 4in1 QCL RGB+UV LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark orange\",\n          \"colors\": [\"#c04d00\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green yellow\",\n          \"colors\": [\"#88ff00\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Salmon\",\n          \"colors\": [\"#ff8888\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#1d9cce\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light green\",\n          \"colors\": [\"#88ff88\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8800\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#cc61cc\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\",\n          \"colors\": [\"#52aeff\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark blue\",\n          \"colors\": [\"#000088\"]\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff88ff\"]\n        },\n        {\n          \"dmxRange\": [180, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Auto Mode / Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 69],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel 1\",\n      \"shortName\": \"4ch1\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Color Presets\",\n        \"Auto Mode / Sound Control\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Color Presets\",\n        \"Auto Mode / Sound Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tmh-14.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TMH-14\",\n  \"shortName\": \"TMH-14\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Victor Hampel\"],\n    \"createDate\": \"2022-06-10\",\n    \"lastModifyDate\": \"2022-06-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.de/manual/286274/Eurolite-Led-Tmh-14.html\"\n    ],\n    \"productPage\": [\n      \"https://www.musikhaus-korn.de/en/eurolite-led-tmh-14-moving-head-zoom-wash/pd/134357\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=h45pZVr19tg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [145, 200, 280],\n    \"weight\": 3.25,\n    \"power\": 65,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3× 12W COB RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 32]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"190deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Colors, color change\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"light blue\",\n          \"colors\": [\"#61b8ff\"]\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"purple\",\n          \"colors\": [\"#ac00ac\"]\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"pink\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"rose\",\n          \"colors\": [\"#ff0080\"]\n        },\n        {\n          \"dmxRange\": [48, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"warm white (mixed from rgbw)\",\n          \"colors\": [\"#ffda95\"]\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"lime\",\n          \"colors\": [\"#a6ff00\"]\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"green\",\n          \"colors\": [\"#00ec27\"]\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"white (mixed rgbw)\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [128, 160],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"fade in and fade out\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"crossfade\"\n        }\n      ]\n    },\n    \"Color change speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Internal programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1\"\n        },\n        {\n          \"dmxRange\": [121, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 2\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Internal programs speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all motors\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Colors, color change\",\n        \"Color change speed\",\n        \"Internal programs\",\n        \"Internal programs speed\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tmh-17.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TMH-17\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Lech\"],\n    \"createDate\": \"2019-08-22\",\n    \"lastModifyDate\": \"2019-08-22\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-08-22\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.1)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51786065-Manual-111842-1.100-eurolite-led-tmh-17-moving-head-spot-en_de.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51786065-eurolite-led-tmh-17-moving-head-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=vWXsAjraBTw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [170, 240, 145],\n    \"weight\": 2.65,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"White 30W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#aaeeff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"200deg\"\n      }\n    },\n    \"Color wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [25, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound to Light\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Maintenance\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan movement\"\n        },\n        {\n          \"dmxRange\": [101, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt movement\"\n        },\n        {\n          \"dmxRange\": [201, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt movement\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color wheel\",\n        \"Gobo Wheel\",\n        \"Strobe\",\n        \"Intensity\",\n        \"Pan/Tilt Speed\",\n        \"Auto Programs\",\n        \"Maintenance\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color wheel\",\n        \"Gobo Wheel\",\n        \"Strobe\",\n        \"Intensity\",\n        \"Pan/Tilt Speed\",\n        \"Auto Programs\",\n        \"Maintenance\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tmh-18.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TMH-18\",\n  \"shortName\": \"TMH18\",\n  \"categories\": [\"Matrix\", \"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"Flo Edelmann\"],\n    \"createDate\": \"2017-05-16\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51786060-MANUAL-1.00-de-en_00095278.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51786060-eurolite-led-tmh-18-moving-head-beam.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=DP71pZH4880\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [260, 145, 360],\n    \"weight\": 5.8,\n    \"power\": 125,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [3, 3]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [3, 3, 1]\n  },\n  \"availableChannels\": {\n    \"Internal Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 1\"\n        },\n        {\n          \"dmxRange\": [68, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 2\"\n        },\n        {\n          \"dmxRange\": [128, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 3\"\n        },\n        {\n          \"dmxRange\": [188, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 4\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal program 5\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"200deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [36, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [56, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [76, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [96, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [116, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [136, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [156, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [176, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [196, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [216, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer off Pan/Tilt\"\n        },\n        {\n          \"dmxRange\": [80, 200],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [201, 207],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [208, 255],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"highlightValue\": 200,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Red-Green\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Red-Blue\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8080\"],\n          \"comment\": \"Red-White\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Green-Blue\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ff80\"],\n          \"comment\": \"Green-White\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8080ff\"],\n          \"comment\": \"Blue-White\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red-Green-Blue\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff80\"],\n          \"comment\": \"Red-Green-White\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff80ff\"],\n          \"comment\": \"Red-Blue-White\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ffff\"],\n          \"comment\": \"Green-Blue-White\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red-Green-Blue-White\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\"\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\"\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\"\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\"\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\"\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 21\"\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 22\"\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 23\"\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 24\"\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 25\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 26\"\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 27\"\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 28\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 29\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 30\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Color Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Internal Programs\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Macros\",\n        \"Macro Speed\",\n        \"Function\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Color Macro Speed\"\n      ]\n    },\n    {\n      \"name\": \"48-channel\",\n      \"shortName\": \"48ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Macros\",\n        \"Macro Speed\",\n        \"Function\",\n        \"Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelYXZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Color Macros\",\n        \"Color Macro Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tmh-7.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TMH-7\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-09-07\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51785973-MANUAL-2.10-en-de_00093407.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51785973-eurolite-led-tmh-7-moving-head-wash.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=XvNNbRJAUKE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [175, 245, 175],\n    \"weight\": 3,\n    \"power\": 75,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18x 3W tricolor LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Pan / Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 40],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 1\",\n          \"helpWanted\": \"What colors can be selected in this channel?\"\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [201, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [31, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Dimmer Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan / Tilt Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Shutter\",\n        \"Dimmer Intensity\",\n        \"Pan fine\",\n        \"Tilt fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tmh-8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TMH-8\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Heiko Fanieng\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-03-29\",\n    \"lastModifyDate\": \"2020-03-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51785963-Anleitung-66256-1.100-eurolite-led-tmh-8-moving-head-spot-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51785963-eurolite-led-tmh-8-moving-head-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Nz6IOcL_Jtc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 175, 245],\n    \"weight\": 3,\n    \"power\": 35,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"10W QCL LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 134],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [135, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"helpWanted\": \"Does this capability start at DMX value 233 or 240? Is this the same in both modes (5ch and 14ch)?\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [32, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [53, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [74, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [95, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pure White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [116, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [137, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [158, 178],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [179, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color change Macro 1\"\n        },\n        {\n          \"dmxRange\": [200, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color change Macro 2\"\n        },\n        {\n          \"dmxRange\": [221, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color change Macro 3\"\n        },\n        {\n          \"dmxRange\": [242, 252],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color change Macro 4\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color change Macro 5\"\n        }\n      ]\n    },\n    \"RGBW Speed\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"Motion Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Motion macro 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Motion macro 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Motion macro 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Motion macro 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Motion macro 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Motion macro 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Motion macro 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Motion macro 8\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [80, 94],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [95, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [125, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [140, 154],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [155, 169],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [185, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 214],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [215, 235],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer / Strobe\",\n        \"Color Macros\",\n        \"Gobo Wheel\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"RGBW Speed\",\n        \"Motion Macros\",\n        \"Gobo Wheel\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tmh-9.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TMH-9\",\n  \"shortName\": \"LEDTMH9\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-09-04\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51785964-MANUAL-1.10-de-en_00096748.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51785964-eurolite-led-tmh-9-moving-head-wash.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=-QyjBCmLol0\",\n      \"https://www.youtube.com/watch?v=qofMKVKaikc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [175, 245, 175],\n    \"weight\": 3,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7x 8W QCL LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [18, 18]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Color macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8080\"],\n          \"comment\": \"Red + White\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ff80\"],\n          \"comment\": \"Green + White\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8080ff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff80\"],\n          \"comment\": \"Red + Green + White\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ffff\"],\n          \"comment\": \"Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff80ff\"],\n          \"comment\": \"Red + Blue + White\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + White\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [31, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Pan / Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer Intensity\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color macros\",\n        \"Shutter\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan / Tilt Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color macros\",\n        \"Shutter\",\n        \"Dimmer Intensity\",\n        \"Pan fine\",\n        \"Tilt fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tmh-x12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TMH-X12\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-11-08\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51785992-Manual-137908-1.200-eurolite-led-tmh-x12-moving-head-spot-Version-ab-22022-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51785992-eurolite-led-tmh-x12-moving-head-spot.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=-jWRxuu8q6U\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [320, 400, 330],\n    \"weight\": 10.5,\n    \"power\": 170,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"120W white COB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#aaccff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#cc00bb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [11, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [19, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [21, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [31, 38],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [41, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [51, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [61, 68],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [71, 78],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [79, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [81, 88],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [89, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [91, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [40, 129],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [135, 220],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        }\n      ]\n    },\n    \"Gobo Stencil Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [64, 126],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo Stencil Shake\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Shake\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Internal Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fade delay off\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fade delay on\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program Auto 1\"\n        },\n        {\n          \"dmxRange\": [76, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program Auto 2\"\n        },\n        {\n          \"dmxRange\": [136, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program Auto 3\"\n        },\n        {\n          \"dmxRange\": [196, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program Auto 4\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 25],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [26, 45],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset others\"\n        },\n        {\n          \"dmxRange\": [46, 103],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan/Tilt\"\n        },\n        {\n          \"dmxRange\": [120, 190],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [191, 205],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [206, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Focus\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Internal Programs\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Focus\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Internal Programs\",\n        \"Reset\",\n        \"Pan fine\",\n        \"Tilt fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-tmh-x25.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED TMH-X25\",\n  \"shortName\": \"TMHX25\",\n  \"categories\": [\"Matrix\", \"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-05-23\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51785991-MANUAL-1.10-de-en_00094116.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51785991-eurolite-led-tmh-x25-moving-head.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=BsuyKJXIU30\",\n      \"https://www.youtube.com/watch?v=hWDPXoVSQlI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [220, 470, 370],\n    \"weight\": 10.6,\n    \"power\": 245,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [5, 5, 1]\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 113,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"18Hz\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"18Hz\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed 1\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed 2\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed 3\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed 4\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [30, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [55, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [80, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [105, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 1\",\n          \"helpWanted\": \"What colors are Color preset 1 until Color preset 10?\"\n        },\n        {\n          \"dmxRange\": [130, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 2\"\n        },\n        {\n          \"dmxRange\": [155, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 3\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 4\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 5\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 6\"\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 7\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 8\"\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 9\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color preset 10\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        }\n      ]\n    },\n    \"Patterns\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"0\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"1\"\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"2\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"3\"\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"4\"\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"5\"\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"6\"\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"7\"\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"8\"\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"9\"\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"A\"\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"B\"\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"C\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"D\"\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"E\"\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"F\"\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"G\"\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"H\"\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"I\"\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"J\"\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"K\"\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"L\"\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"M\"\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"N\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"O\"\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"P\"\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Q\"\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"R\"\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"S\"\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"T\"\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"U\"\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"V\"\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"W\"\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"X\"\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Y\"\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Z\"\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"0–9\"\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"A–Z\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"0–Z\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 1\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 2\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 3\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 4\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 5\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 6\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 7\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 8\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 9\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 10\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 11\"\n        }\n      ]\n    },\n    \"Pattern Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all motors\"\n        },\n        {\n          \"dmxRange\": [100, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Dimmer Speed\",\n        \"Color Presets\",\n        \"Patterns\",\n        \"Pattern Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"Map\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Dimmer Speed\",\n        \"Color Presets\",\n        \"Patterns\",\n        \"Pattern Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Reset\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/led-z-200-tcl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Z-200 TCL\",\n  \"categories\": [\"Effect\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Heiko Fanieng\", \"Ryan Goodwin\"],\n    \"createDate\": \"2023-05-07\",\n    \"lastModifyDate\": \"2023-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51918516-Anleitung-58253-1.100-eurolite-led-z-200-strahleneffekt-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/de/mpn51918516-eurolite-led-z-200-strahleneffekt.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=BH7UX8sXT7Y\",\n      \"https://www.steinigke.de/download/51918516-Video-55873-eurolite-led-z-200-strahleneffekt-de_en_es_fr.flv/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [360, 300, 280],\n    \"weight\": 3,\n    \"power\": 40,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED TCL\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [125, 125]\n    }\n  },\n  \"availableChannels\": {\n    \"Motor Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [21, 170],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"comment\": \"Clockwise and counter clockwise rotation\",\n          \"helpWanted\": \"What does this rotation mean?\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 35],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [36, 70],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"helpWanted\": \"How does the strobe change in this range?\"\n        },\n        {\n          \"dmxRange\": [71, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade\",\n          \"helpWanted\": \"How does the fade change in this range?\"\n        },\n        {\n          \"dmxRange\": [106, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color-change\",\n          \"helpWanted\": \"Which colors are changing at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [141, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color-change + strobe\",\n          \"helpWanted\": \"Which colors are changing at which DMX values? How does the strobe incorperate with it?\"\n        },\n        {\n          \"dmxRange\": [176, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cross-fade\",\n          \"helpWanted\": \"Which colors are changing at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cross-fade + strobe\",\n          \"helpWanted\": \"Which colors are changing at which DMX values? How does the strobe incorperate with it?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Motor Rotation\",\n        \"Program\",\n        \"Program Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/md-2030.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MD-2030\",\n  \"comment\": \"DMX Safety Rotary Motor\",\n  \"categories\": [\"Other\"],\n  \"meta\": {\n    \"authors\": [\"Paul Rogalski\"],\n    \"createDate\": \"2024-10-01\",\n    \"lastModifyDate\": \"2024-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/50301503-Manual-99179-1.100-eurolite-md-2030-dmx-safety-rotary-motor-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn50301503-eurolite-md-2030-dmx-safety-rotary-motor.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [230, 149, 130],\n    \"weight\": 3,\n    \"power\": 13,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Rotation\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/multiflood-pro-ip-smd-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Multiflood Pro IP SMD RGBW\",\n  \"categories\": [\"Blinder\", \"Strobe\", \"Matrix\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"T. Hartwig\"],\n    \"createDate\": \"2019-10-01\",\n    \"lastModifyDate\": \"2019-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/52200930-Anleitung-122489-1.000-eurolite-multiflood-pro-ip-smd-rgbw-strobe-wash-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn52200930-eurolite-multiflood-pro-ip-smd-rgbw-strobe-wash.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=juyIUr8L76w\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [490, 285, 160],\n    \"weight\": 12.5,\n    \"power\": 315,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1320× 0.4W SMD 5050 RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"6\", \"5\", \"4\"],\n        [\"1\", \"2\", \"3\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Background\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"RGBW Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [251, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Special, RGBW full on\"\n        }\n      ]\n    },\n    \"Red Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Red\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Green Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Green\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Blue Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"Blue\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"White Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorIntensity\",\n          \"color\": \"White\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe Duration\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"StrobeDuration\",\n          \"durationStart\": \"short\",\n          \"durationEnd\": \"long\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Random Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Internal Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Programs\",\n          \"helpWanted\": \"At which DMX values can which programs be selected?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [18, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [26, 33],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [34, 41],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [42, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [50, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [58, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light red\",\n          \"colors\": [\"#ff9999\"]\n        },\n        {\n          \"dmxRange\": [66, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [74, 81],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light green\",\n          \"colors\": [\"#99ff99\"]\n        },\n        {\n          \"dmxRange\": [82, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\",\n          \"colors\": [\"#9999ff\"]\n        },\n        {\n          \"dmxRange\": [90, 97],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [98, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full white (RGBW)\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [106, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White (RGB)\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [114, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light yellow\",\n          \"colors\": [\"#ffff99\"]\n        },\n        {\n          \"dmxRange\": [122, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [129, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\"\n        },\n        {\n          \"dmxRange\": [161, 192],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\"\n        },\n        {\n          \"dmxRange\": [193, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"RGBW Strobe\",\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe Duration\",\n        \"Strobe\",\n        \"Random Strobe\",\n        \"Internal Programs\",\n        \"Program Speed\",\n        \"Color Presets\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Strobe\",\n        \"Internal Programs\",\n        \"Program Speed\",\n        \"Color Presets\",\n        \"Red Background\",\n        \"Green Background\",\n        \"Blue Background\",\n        \"White Background\"\n      ]\n    },\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Strobe Duration\",\n        \"Strobe\",\n        \"Random Strobe\",\n        \"Internal Programs\",\n        \"Program Speed\",\n        \"Color Presets\",\n        \"Red Background\",\n        \"Green Background\",\n        \"Blue Background\",\n        \"White Background\"\n      ]\n    },\n    {\n      \"name\": \"31-channel\",\n      \"shortName\": \"31ch\",\n      \"channels\": [\n        \"Dimmer\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Strobe Duration\",\n        \"Strobe\",\n        \"Random Strobe\",\n        \"Internal Programs\",\n        \"Program Speed\",\n        \"Color Presets\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/n-150.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"N-150\",\n  \"categories\": [\"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"Matthias Naumann\"],\n    \"createDate\": \"2020-02-19\",\n    \"lastModifyDate\": \"2020-02-19\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2020-02-19\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.2)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51701970-Manual-58249-1.700-eurolite-n-150-smoke-machine-de_en_es_fr.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51701970-eurolite-n-150-smoke-machine.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Jwrp7I_kYVs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [300, 240, 670],\n    \"weight\": 15,\n    \"power\": 1500,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 13],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutput\": \"off\"\n        },\n        {\n          \"dmxRange\": [14, 127],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"comment\": \"Select volume on channel 2\"\n        },\n        {\n          \"dmxRange\": [128, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Timer mode\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\",\n          \"fogOutput\": \"strong\"\n        }\n      ]\n    },\n    \"Fog Volume\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 70],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"off\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"20%\",\n          \"comment\": \"permanent\"\n        },\n        {\n          \"dmxRange\": [76, 100],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"30%\",\n          \"comment\": \"50sec\"\n        },\n        {\n          \"dmxRange\": [101, 125],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"40%\",\n          \"comment\": \"43sec\"\n        },\n        {\n          \"dmxRange\": [126, 150],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"50%\",\n          \"comment\": \"34sec\"\n        },\n        {\n          \"dmxRange\": [151, 175],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"60%\",\n          \"comment\": \"29sec\"\n        },\n        {\n          \"dmxRange\": [176, 200],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"70%\",\n          \"comment\": \"25sec\"\n        },\n        {\n          \"dmxRange\": [201, 225],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"80%\",\n          \"comment\": \"23sec\"\n        },\n        {\n          \"dmxRange\": [226, 245],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"90%\",\n          \"comment\": \"21sec\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"100%\",\n          \"comment\": \"20sec\"\n        }\n      ]\n    },\n    \"Timer Duration\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Time\",\n          \"time\": \"1s\"\n        },\n        {\n          \"dmxRange\": [6, 29],\n          \"type\": \"Time\",\n          \"time\": \"13s\"\n        },\n        {\n          \"dmxRange\": [30, 54],\n          \"type\": \"Time\",\n          \"time\": \"33s\"\n        },\n        {\n          \"dmxRange\": [55, 79],\n          \"type\": \"Time\",\n          \"time\": \"53s\"\n        },\n        {\n          \"dmxRange\": [80, 104],\n          \"type\": \"Time\",\n          \"time\": \"73s\"\n        },\n        {\n          \"dmxRange\": [105, 129],\n          \"type\": \"Time\",\n          \"time\": \"92s\"\n        },\n        {\n          \"dmxRange\": [130, 154],\n          \"type\": \"Time\",\n          \"time\": \"112s\"\n        },\n        {\n          \"dmxRange\": [155, 179],\n          \"type\": \"Time\",\n          \"time\": \"131s\"\n        },\n        {\n          \"dmxRange\": [180, 204],\n          \"type\": \"Time\",\n          \"time\": \"151s\"\n        },\n        {\n          \"dmxRange\": [205, 229],\n          \"type\": \"Time\",\n          \"time\": \"170s\"\n        },\n        {\n          \"dmxRange\": [230, 254],\n          \"type\": \"Time\",\n          \"time\": \"190s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Time\",\n          \"time\": \"200s\"\n        }\n      ]\n    },\n    \"Timer Interval\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Time\",\n          \"time\": \"1s\"\n        },\n        {\n          \"dmxRange\": [6, 29],\n          \"type\": \"Time\",\n          \"time\": \"13s\"\n        },\n        {\n          \"dmxRange\": [30, 54],\n          \"type\": \"Time\",\n          \"time\": \"33s\"\n        },\n        {\n          \"dmxRange\": [55, 79],\n          \"type\": \"Time\",\n          \"time\": \"53s\"\n        },\n        {\n          \"dmxRange\": [80, 104],\n          \"type\": \"Time\",\n          \"time\": \"73s\"\n        },\n        {\n          \"dmxRange\": [105, 129],\n          \"type\": \"Time\",\n          \"time\": \"92s\"\n        },\n        {\n          \"dmxRange\": [130, 154],\n          \"type\": \"Time\",\n          \"time\": \"112s\"\n        },\n        {\n          \"dmxRange\": [155, 179],\n          \"type\": \"Time\",\n          \"time\": \"131s\"\n        },\n        {\n          \"dmxRange\": [180, 204],\n          \"type\": \"Time\",\n          \"time\": \"151s\"\n        },\n        {\n          \"dmxRange\": [205, 229],\n          \"type\": \"Time\",\n          \"time\": \"170s\"\n        },\n        {\n          \"dmxRange\": [230, 254],\n          \"type\": \"Time\",\n          \"time\": \"190s\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Time\",\n          \"time\": \"200s\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Fog Volume\",\n        \"Timer Duration\",\n        \"Timer Interval\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/tmh-xb-130.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"TMH XB-130\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Henry Haage\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-01-23\",\n    \"lastModifyDate\": \"2020-01-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51786810-Anleitung-114498-1.100-eurolite-tmh-xb-130-moving-head-beam-de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51786810-eurolite-tmh-xb-130-moving-head-beam.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=4KPILAbN-0M\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [299, 435, 252],\n    \"weight\": 10,\n    \"power\": 170,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"Osram Sirius HRI 132W discharge lamp\",\n      \"colorTemperature\": 4000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [1, 1]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Pan/Tilt Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"in sequences\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [84, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [90, 98],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [99, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [108, 116],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [117, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [126, 134],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [135, 143],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [144, 152],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [153, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [162, 170],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [171, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [180, 188],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [189, 206],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [207, 223],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [75, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [90, 98],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [99, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [108, 116],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [117, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [126, 134],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [135, 143],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [144, 152],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [153, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [162, 170],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [171, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [180, 188],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [189, 197],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [198, 206],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [207, 215],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [225, 239],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism + Frost\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Prism\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"off\",\n          \"frostIntensityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [4, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [132, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all motors\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset only Pan/Tilt\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset only colors\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset only gobo\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset shutter\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset other\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Off\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display On\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp Off\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp On\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Hibernation\"\n        },\n        {\n          \"dmxRange\": [96, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Use1\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Prism + Frost\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"Use2\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Pan/Tilt Function\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Prism + Frost\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eurolite/ts-2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"TS-2 DMX-Scanner\",\n  \"shortName\": \"TS-2\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"oxim\", \"Luke Nelson\"],\n    \"createDate\": \"2023-04-20\",\n    \"lastModifyDate\": \"2023-04-20\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.steinigke.fr/en/mpn51785765-eurolite-ts-2-scan.html\"\n    ],\n    \"manual\": [\n      \"https://www.steinigke.fr/download/51785765-Manual-9543-1.400-eurolite-ts-2-scan-de_en_es_fr.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=w5T1t7J5q_o\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [195, 290, 295],\n    \"weight\": 4,\n    \"power\": 115,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff0080\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#00ff80\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Yellow\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red and Blue\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow and Green\",\n          \"colors\": [\"#ffff00\", \"#00ff00\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 7\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 8\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 9\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 10\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 11\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 12\"\n        },\n        {\n          \"type\": \"Closed\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"130deg\"\n      }\n    },\n    \"Tilt\": {\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"90deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [18, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [36, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [54, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [72, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [90, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [108, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [126, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [144, 161],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [162, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [180, 197],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [198, 215],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [216, 233],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [234, 251],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14,\n          \"helpWanted\": \"Is this a bi-colour slot or halfway between two?\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15,\n          \"helpWanted\": \"Is this a bi-colour slot or halfway between two?\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [84, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [91, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 238],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 0,\n          \"slotNumberEnd\": 1,\n          \"comment\": \"Strobe-effect with increasing speed\"\n        },\n        {\n          \"dmxRange\": [239, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        }\n      ]\n    },\n    \"Lamp\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Lamp\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/event-lighting/par12x12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Par12x12\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ian MacColl\"],\n    \"createDate\": \"2019-08-26\",\n    \"lastModifyDate\": \"2019-08-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdn.shopify.com/s/files/1/0304/0549/files/PAR12_V2.1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20250426133413/https://eventlighting.com.au/products/par12x12\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=MbdnJqu0MiQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [263, 293, 109],\n    \"weight\": 3.2,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 12W RGBWAUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [20, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Strobe simple\": {\n      \"name\": \"Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"warm\",\n        \"colorTemperatureEnd\": \"cold\"\n      }\n    },\n    \"Color Macro / Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colors\": [\"#ff0000\", \"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colors\": [\"#ffff00\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colors\": [\"#00ff00\", \"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colors\": [\"#00ffff\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colors\": [\"#0000ff\", \"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colors\": [\"#ff00ff\", \"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colors\": [\"#ffffff\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [180, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"warm\",\n          \"colorTemperatureEnd\": \"cold\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"RGBWAUV colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 90],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"36 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 131],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"RGBWAUV colors, RGBW model\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [132, 172],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"36 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [173, 213],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macros\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [214, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use dimmer curve from control board setting\"\n        },\n        {\n          \"dmxRange\": [10, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16bit linear dimmer 1\"\n        },\n        {\n          \"dmxRange\": [58, 106],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16bit non-linear dimmer 2\"\n        },\n        {\n          \"dmxRange\": [107, 155],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16bit non-linear dimmer 3\"\n        },\n        {\n          \"dmxRange\": [156, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16bit non-linear dimmer 4\"\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"8bit linear dimmer 5\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Color Temperature\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe simple\",\n        \"Color Macro / Temperature\",\n        \"Auto Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/event-lighting/par5x12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Par5x12\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-08-26\",\n    \"lastModifyDate\": \"2019-08-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdn.shopify.com/s/files/1/0304/0549/files/PAR12_V2.1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20250218184018/https://event-lighting.com.au/products/par5x12\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=6dmSNkOVrCQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [207, 227, 120],\n    \"weight\": 1.9,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5× 12W RGBWAUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [20, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Strobe simple\": {\n      \"name\": \"Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"warm\",\n        \"colorTemperatureEnd\": \"cold\"\n      }\n    },\n    \"Color Macro / Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colors\": [\"#ff0000\", \"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colors\": [\"#ffff00\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colors\": [\"#00ff00\", \"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colors\": [\"#00ffff\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colors\": [\"#0000ff\", \"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colors\": [\"#ff00ff\", \"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colors\": [\"#ffffff\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [180, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"warm\",\n          \"colorTemperatureEnd\": \"cold\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"RGBWAUV colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 90],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"36 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 131],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"RGBWAUV colors, RGBW model\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [132, 172],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"36 colors\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [173, 213],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macros\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [214, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use dimmer curve from control board setting\"\n        },\n        {\n          \"dmxRange\": [10, 57],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16bit linear dimmer 1\"\n        },\n        {\n          \"dmxRange\": [58, 106],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16bit non-linear dimmer 2\"\n        },\n        {\n          \"dmxRange\": [107, 155],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16bit non-linear dimmer 3\"\n        },\n        {\n          \"dmxRange\": [156, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"16bit non-linear dimmer 4\"\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"8bit linear dimmer 5\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Color Temperature\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe simple\",\n        \"Color Macro / Temperature\",\n        \"Auto Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/evolight/colours-archspot-54-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Colours Archspot 54 RGB\",\n  \"shortName\": \"Archspot54\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Michael Stiller\"],\n    \"createDate\": \"2019-01-05\",\n    \"lastModifyDate\": \"2019-01-05\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.gemmiluci.it/download/Manuali%20test%20Mobili%20e%20Led/ParLed54%20Evolight.pdf\"\n    ]\n  },\n  \"helpWanted\": \"Which LEDs are controlled by the pixels 1, 2, 3 in the RGB 12-channel mode?\",\n  \"physical\": {\n    \"dimensions\": [260, 220, 230],\n    \"weight\": 4,\n    \"power\": 58,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18x3W RGB LEDs\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1\", \"2\", \"3\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": [\"1\", \"2\", \"3\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Hue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Rainbow\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectPreset\": \"ColorFade\",\n        \"helpWanted\": \"At which DMX value is this effect disabled?\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"CTO\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2500K\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2900K\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4500K\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5400K\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7000K\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"00001 HSV 4-channel\",\n      \"shortName\": \"HSV-4ch\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"00002 RGB 6-channel\",\n      \"shortName\": \"RGB-6ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe\",\n        \"Rainbow\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"00003 RGB 12-channel\",\n      \"shortName\": \"RGB-12ch\",\n      \"channels\": [\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        \"Red 2\",\n        \"Green 2\",\n        \"Blue 2\",\n        \"Red 3\",\n        \"Green 3\",\n        \"Blue 3\",\n        \"Strobe\",\n        \"Rainbow\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"00004 HSV-W 5-channel\",\n      \"shortName\": \"HSVW-5ch\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\",\n        \"Strobe\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"00005 RGB 3-channel\",\n      \"shortName\": \"RGB-3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"00006 RGB-CTO 7-channel\",\n      \"shortName\": \"RGB-CTO-7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe\",\n        \"Rainbow\",\n        \"Intensity\",\n        \"CTO\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/explo/gasprojector-gx2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Gasprojector GX2\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Gloryfire\"],\n    \"createDate\": \"2019-05-30\",\n    \"lastModifyDate\": \"2019-05-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.explo.at/_Resources/Persistent/459c14f10f9fddad03748a108704cb345c719266/Gasbrenner%20GX2%202.0%20EN.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.explo.at/en/effektgeraete/gas/gx2-12v.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=nRJiaLzVk0Y\",\n      \"https://www.youtube.com/watch?v=ut26zDS3Z4c\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [260, 390, 260],\n    \"weight\": 6.8,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Ignition\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 252],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No ignition\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single ignition\"\n        }\n      ]\n    },\n    \"Valve Opening Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Saftety zone\"\n        },\n        {\n          \"dmxRange\": [11, 13],\n          \"type\": \"Time\",\n          \"timeStart\": \"20ms\",\n          \"timeEnd\": \"60ms\",\n          \"comment\": \"Small fireball\"\n        },\n        {\n          \"dmxRange\": [14, 34],\n          \"type\": \"Time\",\n          \"timeStart\": \"80ms\",\n          \"timeEnd\": \"480ms\",\n          \"comment\": \"Flame pillar\"\n        },\n        {\n          \"dmxRange\": [35, 60],\n          \"type\": \"Time\",\n          \"timeStart\": \"500ms\",\n          \"timeEnd\": \"1000ms\",\n          \"comment\": \"Larger flames\"\n        },\n        {\n          \"dmxRange\": [61, 200],\n          \"type\": \"Time\",\n          \"timeStart\": \"1020ms\",\n          \"timeEnd\": \"3800ms\",\n          \"comment\": \"Extra large flames\"\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flame every 5 seconds\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Safety zone\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"channels\": [\n        \"Ignition\",\n        \"Valve Opening Time\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/explo/x2-wave-flamer.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"X2 Wave Flamer\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Gloryfire\"],\n    \"createDate\": \"2019-07-20\",\n    \"lastModifyDate\": \"2019-07-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.explo.at/_Resources/Persistent/354c199da6815d6c3da601b8359861aed2250b07/X2%20Wave%20Flamer%20v1.3.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.explo.at/en/effektgeraete/liquid/x2-wave-flamer-1.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=yjR-8Thzh50\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [335, 365, 560],\n    \"weight\": 27,\n    \"power\": 350,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Angle\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"-105deg\",\n        \"angleEnd\": \"105deg\"\n      }\n    },\n    \"Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"stop\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Ignition\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 253],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No ignition\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single ignition\"\n        }\n      ]\n    },\n    \"Opening Time\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"Time\",\n          \"timeStart\": \"0ms\",\n          \"timeEnd\": \"2540ms\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Time\",\n          \"time\": \"long\",\n          \"comment\": \"permanent, stops at the latest of 2500ms\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"Effect\",\n          \"effectName\": \"No function\"\n        },\n        {\n          \"dmxRange\": [3, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"-105°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"-90°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [8, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"-75°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"-60°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [13, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"-45°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"-30°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [18, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"-15°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [21, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"0°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [23, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"15°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [26, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"30°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"45°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [31, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"60°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"75°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [36, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"90°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"105°, single ignition short flame\",\n          \"duration\": \"110ms\"\n        },\n        {\n          \"dmxRange\": [41, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"-105°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"-90°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [46, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"-75°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"-60°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [51, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"-45°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [54, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"-30°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"-15°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [59, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"0°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [62, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"15°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [64, 66],\n          \"type\": \"Effect\",\n          \"effectName\": \"30°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [67, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"45°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [69, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"60°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [72, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"75°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [74, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"90°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [77, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"105°, single ignition long flame\",\n          \"duration\": \"410ms\"\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence from 1-15, short flame\",\n          \"duration\": \"2.4s\"\n        },\n        {\n          \"dmxRange\": [82, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence from 15-1, short flame\",\n          \"duration\": \"2.4s\"\n        },\n        {\n          \"dmxRange\": [85, 86],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 5>8>11, short flame\",\n          \"duration\": \"0.58s\"\n        },\n        {\n          \"dmxRange\": [87, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 11>8>5, short flame\",\n          \"duration\": \"0.58s\"\n        },\n        {\n          \"dmxRange\": [90, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 6>10, short flame\",\n          \"duration\": \"0.39s\"\n        },\n        {\n          \"dmxRange\": [92, 94],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 10>6, short flame\",\n          \"duration\": \"0.39s\"\n        },\n        {\n          \"dmxRange\": [95, 96],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 4>6>8>10>12, short flame\",\n          \"duration\": \"0.9s\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 12>10>8>6>4, short flame\",\n          \"duration\": \"0.9s\"\n        },\n        {\n          \"dmxRange\": [100, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 8>6>10>4>12, short flame\",\n          \"duration\": \"1s\"\n        },\n        {\n          \"dmxRange\": [102, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 8>10>6>12>4, short flame\",\n          \"duration\": \"1s\"\n        },\n        {\n          \"dmxRange\": [105, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence from 1-15, long flame\",\n          \"duration\": \"6.89s\"\n        },\n        {\n          \"dmxRange\": [108, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence from 15-1, long flame\",\n          \"duration\": \"6.89s\"\n        },\n        {\n          \"dmxRange\": [110, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 5>8>11, long flame\",\n          \"duration\": \"1.48s\"\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 11>8>5, long flame\",\n          \"duration\": \"1.48s\"\n        },\n        {\n          \"dmxRange\": [115, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 6>10, long flame\",\n          \"duration\": \"0.99s\"\n        },\n        {\n          \"dmxRange\": [118, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 10>6, long flame\",\n          \"duration\": \"0.99s\"\n        },\n        {\n          \"dmxRange\": [120, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 4>6>8>10>12, long flame\",\n          \"duration\": \"2.4s\"\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 12>10>8>6>4, long flame\",\n          \"duration\": \"2.4s\"\n        },\n        {\n          \"dmxRange\": [125, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 8>6>10>4>12, long flame\",\n          \"duration\": \"2.53s\"\n        },\n        {\n          \"dmxRange\": [128, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 8>16>12>4, long flame\",\n          \"duration\": \"2.53s\"\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 5>11, middle\",\n          \"duration\": \"1.79s\"\n        },\n        {\n          \"dmxRange\": [133, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 11>5, middle\",\n          \"duration\": \"1.79s\"\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"BIG wave sequence 1>15, long\",\n          \"duration\": \"3.93s\"\n        },\n        {\n          \"dmxRange\": [138, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"BIG wave sequence 15>1, long\",\n          \"duration\": \"3.93s\"\n        },\n        {\n          \"dmxRange\": [141, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 8>1, middle\",\n          \"duration\": \"2.26s\"\n        },\n        {\n          \"dmxRange\": [143, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 8>15, middle\",\n          \"duration\": \"2.26s\"\n        },\n        {\n          \"dmxRange\": [146, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 1>8, middle\",\n          \"duration\": \"2.26s\"\n        },\n        {\n          \"dmxRange\": [148, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 15>8, middle\",\n          \"duration\": \"2.26s\"\n        },\n        {\n          \"dmxRange\": [151, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 8>11, short\",\n          \"duration\": \"1.19s\"\n        },\n        {\n          \"dmxRange\": [153, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 8>5, short\",\n          \"duration\": \"1.19s\"\n        },\n        {\n          \"dmxRange\": [156, 158],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 5>8, short\",\n          \"duration\": \"1.19s\"\n        },\n        {\n          \"dmxRange\": [159, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave sequence 11>8, short\",\n          \"duration\": \"1.19s\"\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 2>14, short flame\",\n          \"duration\": \"0.48s\"\n        },\n        {\n          \"dmxRange\": [164, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 14>2, short flame\",\n          \"duration\": \"0.48s\"\n        },\n        {\n          \"dmxRange\": [166, 168],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 2>14, long flame\",\n          \"duration\": \"1.23s\"\n        },\n        {\n          \"dmxRange\": [169, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Step sequence 14>2, long flame\",\n          \"duration\": \"1.23s\"\n        },\n        {\n          \"dmxRange\": [171, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"Unknown\",\n          \"helpWanted\": \"Which effect is this (program 67)?\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Unknown\",\n          \"helpWanted\": \"Which effect is this (program 68)?\"\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"Effect\",\n          \"effectName\": \"Unknown\",\n          \"helpWanted\": \"Which effect is this (program 69)?\"\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Unknown\",\n          \"helpWanted\": \"Which effect is this (program 70)?\"\n        },\n        {\n          \"dmxRange\": [182, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Test Mode\"\n        },\n        {\n          \"dmxRange\": [50, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Armed Mode\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Test Mode\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Angle\",\n        \"Speed\",\n        \"Ignition\",\n        \"Opening Time\",\n        \"Programs\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/eyourlife/led-rgbw-54x3-par64.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED RGBW 54x3 Par64\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Moss\"],\n    \"createDate\": \"2019-12-23\",\n    \"lastModifyDate\": \"2019-12-26\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-12-23\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.2)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://medias.audiofanzine.com/files/eyourlife-54-led-par-rgbw-479942.pdf\"\n    ]\n  },\n  \"helpWanted\": \"Can you provide a link to a product page?\",\n  \"physical\": {\n    \"dimensions\": [230, 220, 255],\n    \"weight\": 4.5,\n    \"power\": 170,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Macros/Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff69b4\"]\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright green\",\n          \"colors\": [\"#90ee90\"]\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright yellow\",\n          \"colors\": [\"#ffffe0\"]\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright magenta\",\n          \"colors\": [\"#ff55ff\"]\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale cyan\",\n          \"colors\": [\"#e0ffff\"]\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm white\",\n          \"colors\": [\"#faebd7\"]\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Which speed is this?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Color Macros/Effects\",\n        \"Speed\"\n      ]\n    },\n    {\n      \"name\": \"EYL2 variant 8-channel\",\n      \"shortName\": \"eyl2\",\n      \"channels\": [\n        \"Strobe\",\n        \"Color Macros/Effects\",\n        \"Speed\",\n        \"Master Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fiilex/p3-color.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"P3 Color\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"helpWanted\": \"Please add the missing modes 6, 8, 14, 16, 40-49, 55-62, 68-77.\",\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-08-04\",\n    \"lastModifyDate\": \"2021-08-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://fiilex.com/downloads/P3/5870148-005_A2_USER%20GUIDE%20for%20P3%20COLOR.pdf\",\n      \"https://fiilex.com/downloads/DMX/DMX_Mapping_Color_Series_210903A.pdf\"\n    ],\n    \"productPage\": [\n      \"https://fiilex.com/products/P3_Color.php\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 48\n  },\n  \"physical\": {\n    \"dimensions\": [119, 142, 206],\n    \"weight\": 0.84,\n    \"power\": 90,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 65]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Intensity\": {\n      \"fineChannelAliases\": [\"Master Intensity fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2000K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    },\n    \"CCT Base\": {\n      \"name\": \"Color Temperature Base\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 99],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [100, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 8bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"Green-Magenta Point 16bit\": {\n      \"name\": \"Green-Magenta Point\",\n      \"fineChannelAliases\": [\"Green-Magenta Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [10, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"Fan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [10, 69],\n          \"type\": \"Rotation\",\n          \"speed\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Dimming\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use current setting in fixture\"\n        },\n        {\n          \"dmxRange\": [10, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sharp dimming\"\n        },\n        {\n          \"dmxRange\": [100, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth dimming\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Crossfade\": {\n      \"fineChannelAliases\": [\"Crossfade fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"CCT … Color Mix\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Gel Filter\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\",\n          \"colors\": [\"#ffb783\"]\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\",\n          \"colors\": [\"#ffc069\"]\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\",\n          \"colors\": [\"#ffba45\"]\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Flame\",\n          \"colors\": [\"#ff391b\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden Amber\",\n          \"colors\": [\"#ff8944\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff3914\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Color Pink\",\n          \"colors\": [\"#ffaaaa\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\",\n          \"colors\": [\"#ff9ba1\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose Purple\",\n          \"colors\": [\"#ff95e0\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\",\n          \"colors\": [\"#e5c7ff\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"No Color Blue\",\n          \"colors\": [\"#00a0ff\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\",\n          \"colors\": [\"#00c2ff\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Blue\",\n          \"colors\": [\"#64deff\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\",\n          \"colors\": [\"#a7ff58\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue Green\",\n          \"colors\": [\"#ffe5b3\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gel 1\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gel 2\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gel 3\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gel 4\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gel 5\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Reserved for future use\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1: CCT 8bit\",\n      \"shortName\": \"M01\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"2: HSI 8bit\",\n      \"shortName\": \"M02\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"3: RGBW 8bit\",\n      \"shortName\": \"M03\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"4: CCT + HSI 8bit\",\n      \"shortName\": \"M04\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Crossfade\",\n        \"Hue\",\n        \"Saturation\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"5: CCT + RGBW 8bit\",\n      \"shortName\": \"M05\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Crossfade\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"7: GEL 8bit\",\n      \"shortName\": \"M07\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Gel Filter\",\n        \"CCT Base\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"9: CCT 16bit\",\n      \"shortName\": \"M09\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"10: HSI 16bit\",\n      \"shortName\": \"M10\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"11: RGBW 16bit\",\n      \"shortName\": \"M11\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"12: CCT + HSI 16bit\",\n      \"shortName\": \"M12\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"13: CCT + RGBW 16bit\",\n      \"shortName\": \"M13\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"15: GEL 16bit\",\n      \"shortName\": \"M15\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Gel Filter\",\n        \"CCT Base\",\n        \"Fan\",\n        \"Dimming\",\n        \"Strobe\",\n        \"Reserved for future use\"\n      ]\n    },\n    {\n      \"name\": \"50: EZ CCT 8bit\",\n      \"shortName\": \"M50\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"51: EZ HSI 8bit\",\n      \"shortName\": \"M51\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"52: EZ RGBW 8bit\",\n      \"shortName\": \"M42\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"53: EZ CCT + HSI 8bit\",\n      \"shortName\": \"M53\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Crossfade\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"54: EZ CCT + RGBW 8bit\",\n      \"shortName\": \"M54\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Color Temperature\",\n        \"Green-Magenta Point 8bit\",\n        \"Crossfade\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"63: EZ CCT 16bit\",\n      \"shortName\": \"M63\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"64: EZ HSI 16bit\",\n      \"shortName\": \"M64\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"65: EZ RGBW 16bit\",\n      \"shortName\": \"M65\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"66: EZ CCT + HSI 16bit\",\n      \"shortName\": \"M66\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"67: EZ CCT + RGBW 16bit\",\n      \"shortName\": \"M67\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Master Intensity fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point 16bit\",\n        \"Green-Magenta Point 16bit fine\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/flash-professional/led-moving-head-150w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Moving Head 150W\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-11-21\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://flash-butrym.pl/en_US/p/file/e1559f5a07f45db28b9ecaea49bc8fdd/7100506-LED-MOVING-HEAD-150W-2-31-AUTO-FOCUS%2C-ROTO-PRISM.pdf\"\n    ],\n    \"productPage\": [\n      \"https://flash-butrym.pl/en_US/p/4x-LED-MOVING-HEAD-150W-2-31-ROTO-PRISM-SET/559\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=LHWkp4Wu2io\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 452, 256],\n    \"weight\": 12,\n    \"power\": 189,\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 150W white LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [2, 28]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00cc\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Turquoise\",\n          \"colors\": [\"#00ffcc\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffaaff\"]\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"10%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"25%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"40%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"50%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"75%\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Biohazard\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Fuzzy rays\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bar\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Striped shutter\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Life\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Flower\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Arrows\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Stars\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Show Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 1\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 2\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 3\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 4\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 28\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 29\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 30\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 31\"\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [19, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [22, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [25, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [28, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [31, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [34, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [37, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [43, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [46, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [52, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [55, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [58, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [61, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [17, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [26, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [35, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [44, 52],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [53, 61],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [62, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [68, 72],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [73, 81],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [82, 90],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [91, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [100, 108],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [109, 117],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [27, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [36, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [45, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [54, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 73],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [74, 83],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [84, 93],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [94, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 113],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [114, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Angle / Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 128],\n          \"type\": \"Zoom\",\n          \"angle\": \"20deg\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Special Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable blackout during Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable blackout during Color change\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during Color change\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable blackout during Gobo change\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during Gobo change\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt reset\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Effect reset\"\n        },\n        {\n          \"dmxRange\": [160, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All reset\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable blackout during Pan/Tilt movement / Color/Gobo change\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during Pan/Tilt movement / Color/Gobo change\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"17-channel\",\n      \"shortName\": \"17ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Show Mode\",\n        \"Pan/Tilt Macro\",\n        \"Macro Speed\",\n        \"Color Wheel\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Angle / Frost\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Special Function\"\n      ]\n    },\n    {\n      \"name\": \"20-channel\",\n      \"shortName\": \"20ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Show Mode\",\n        \"Pan/Tilt Macro\",\n        \"Macro Speed\",\n        \"Color Wheel\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Angle / Frost\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Special Function\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/flash-professional/led-par-64-cob-300w-rgbwauv.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR 64 COB 300W RGBWAUV\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Jeppe Toftdahl cohrt\"],\n    \"createDate\": \"2019-05-30\",\n    \"lastModifyDate\": \"2019-05-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://flash-butrym.pl/en_US/p/file/cd8d1457c24013dd694ecd6d9294b1bd/P7100400-LED-PAR-COB-300W-RGBWA-UV.pdf\"\n    ],\n    \"productPage\": [\n      \"https://flash-butrym.pl/en_US/p/LED-PAR-64-300W-6in1-COB-RGBWA-UV-BARNDOOR/406\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=TJtqvw6y7ss\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [270, 280, 240],\n    \"weight\": 3.4,\n    \"power\": 354,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"300W COB RGBAUV LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [37, 37]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"Is this a static color and if yes, which color is this? Same for following colors.\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Color Change\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"Is this a color jump/fade effect or a static color? Same for following effects.\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Color 12\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel 1\",\n      \"shortName\": \"10ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Macro\",\n        \"Color Change\"\n      ]\n    },\n    {\n      \"name\": \"10-channel 2\",\n      \"shortName\": \"10ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Macro\",\n        \"Color Change\",\n        \"Amber\",\n        \"UV\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/flash-professional/led-par-64-slim-7x10w-rgbw-mk2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR 64 SLIM 7x10W RGBW Mk2\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flash Professional\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-04-09\",\n    \"lastModifyDate\": \"2019-04-09\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2019-04-09\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.0)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://flash-butrym.pl/en/downloads/d/515\"\n    ],\n    \"productPage\": [\n      \"https://flash-butrym.pl/en/par-slim-p710-25-f-wdmx\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=---UxzqLBVM\",\n      \"https://www.youtube.com/watch?v=dwslAXSCMIc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [255, 270, 110],\n    \"weight\": 1.3,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7× RGBW LED\",\n      \"colorTemperature\": 9000,\n      \"lumens\": 10000\n    },\n    \"lens\": {\n      \"name\": \"PC\",\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color / Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0004\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff8082\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#80ff80\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#8080ff\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff6800\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mint\",\n          \"colors\": [\"#6cffc2\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#b3e9ff\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Cyan\",\n          \"colors\": [\"#80ffff\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Magenta\",\n          \"colors\": [\"#ff80ff\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Yellow\",\n          \"colors\": [\"#ffff80\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"9000K\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffe0\"],\n          \"colorTemperature\": \"6500K\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#feffbe\"],\n          \"colorTemperature\": \"5600K\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffb4\"],\n          \"colorTemperature\": \"5000K\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#feff8f\"],\n          \"colorTemperature\": \"4500K\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffdf8b\"],\n          \"colorTemperature\": \"3200K\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffcb70\"],\n          \"colorTemperature\": \"2500K\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ff9f31\"],\n          \"colorTemperature\": \"2200K\",\n          \"switchChannels\": {\n            \"Speed\": \"Pulse Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Macro 1\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Macro 2\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Macro 3\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Macro 4\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macro 5\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macro 6\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macro 7\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macro 8\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macro 9\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macro 10\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Macro 11\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 235],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Sound mode 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Sound mode 2\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Sound mode 3\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Sound mode 4\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed\": \"Macro Speed\"\n          }\n        }\n      ]\n    },\n    \"Pulse Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"pulse\"\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\",\n        \"comment\": \"macro\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Classic 6\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"Classic 8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color / Macro\",\n        \"Speed\"\n      ]\n    },\n    {\n      \"name\": \"Pro 6\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"Pro 7\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"RGB 16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"Flash A-DMX\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        null,\n        \"Strobe\",\n        \"Color / Macro\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fovitec/600xb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"600XB\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2021-08-20\",\n    \"lastModifyDate\": \"2021-08-20\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://web.archive.org/web/20230610152318/https://www.fovitec.com/products/600xb-bi-color-led-panel-with-dmx\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [394, 399, 76],\n    \"power\": 36,\n    \"bulb\": {\n      \"type\": \"600× LED\",\n      \"lumens\": 1420\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"3200K\",\n        \"colorTemperatureEnd\": \"5600K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fractal-lights/par-led-7x10w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PAR LED 7x10W\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Marek Jędrzejewski\"],\n    \"createDate\": \"2020-02-16\",\n    \"lastModifyDate\": \"2020-02-16\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://fractallights.com/produkty/PAR_LED_7_x_9W_7_x_10W_7_x_12W/\",\n      \"https://fractallights.com/catalog/#p=6\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 180, 110],\n    \"weight\": 2,\n    \"power\": 90,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7×10W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual control\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color presets\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"black between colors\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"comment\": \"select color or color change\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Sound Colors\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Colors\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [31, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [62, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [93, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [124, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [155, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [186, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [217, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Mode\",\n        \"Color Presets / Effect Speed / Sound Colors\"\n      ]\n    },\n    {\n      \"name\": \"RGBW\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fractal-lights/par-led-7x12w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PAR LED 7x12W\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Marek Jędrzejewski\", \"Felix Edelmann\"],\n    \"createDate\": \"2020-02-16\",\n    \"lastModifyDate\": \"2020-02-16\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://fractallights.com/produkty/PAR_LED_7_x_9W_7_x_10W_7_x_12W/\",\n      \"https://fractallights.com/catalog/#p=6\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 180, 110],\n    \"weight\": 2,\n    \"power\": 100,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7×12W RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual control\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color presets\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"black between colors\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"comment\": \"select color or color change\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Sound Colors\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Colors\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [31, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [62, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [93, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [124, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [155, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [186, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [217, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Strobe\",\n        \"Mode\",\n        \"Color Presets / Effect Speed / Sound Colors\"\n      ]\n    },\n    {\n      \"name\": \"RGBWA\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fractal-lights/par-led-7x9w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PAR LED 7x9W\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Marek Jędrzejewski\", \"Felix Edelmann\"],\n    \"createDate\": \"2020-02-16\",\n    \"lastModifyDate\": \"2020-02-16\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://fractallights.com/produkty/PAR_LED_7_x_9W_7_x_10W_7_x_12W/\",\n      \"https://fractallights.com/catalog/#p=6\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2CFWcla3nOc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 180, 110],\n    \"weight\": 2,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7×9W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual control\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color presets\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"dimming between colors\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"comment\": \"select color or color change\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed / Sound Colors\": \"Sound Colors\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [33, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Colors\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [31, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [62, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [93, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [124, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [155, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [186, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [217, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Mode\",\n        \"Color Presets / Effect Speed / Sound Colors\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/led-pot-12-1w-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Pot 12×1W RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dennis Fischer\"],\n    \"createDate\": \"2019-11-01\",\n    \"lastModifyDate\": \"2019-11-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/377666_c_377666_r4_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_led_pot_12x1w_rgbw.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i4829p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [172, 130, 168],\n    \"weight\": 0.76,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 1W TrueColour LED (3× red, 3× green, 3× blue, 3× white)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro activation\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [17, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 01\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 02\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 03\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 04\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [85, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 05\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 06\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [119, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 07\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 08\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [153, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 09\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [187, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [204, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color Presets / Program Speed\": \"Program Speed\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Off\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff9600\"]\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffb400\"]\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff008c\"]\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\",\n          \"colors\": [\"#ffc828\"]\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 100],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity Sound to Light\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Program\",\n        \"Color Presets / Program Speed\",\n        \"Shutter / Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/led-pot-12x1w-qcl-rgb-ww-15.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Pot 12x1W QCL RGB WW 15°\",\n  \"shortName\": \"FunGenLEDPotQCL15\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Paul Rogalski\"],\n    \"createDate\": \"2024-09-30\",\n    \"lastModifyDate\": \"2024-09-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_409499_428047_512677_512675_v5_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_led_pot_12x1w_qcl_rgb_ww.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i5958p8_yd59vq8a.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [168, 172, 130],\n    \"weight\": 0.42,\n    \"power\": 17,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 1W QCL-LEDs (RGBWW)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 01\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [17, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 02\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 03\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 04\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 05\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [85, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 06\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 07\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [119, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 08\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 09\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [153, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [187, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [204, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"Sound Control\"\n          }\n        }\n      ]\n    },\n    \"No Function\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blackout\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ff9600\"]\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ffb400\"]\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff008c\"]\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#ffc828\"]\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Sound Control\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound program selection\",\n        \"soundControlled\": true\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Program\",\n        \"No Function / Color Presets / Sound Control\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/led-pot-12x1w-qcl-rgb-ww-40.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Pot 12x1W QCL RGB WW 40°\",\n  \"shortName\": \"FunGenLEDPotQCL40\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Minno\", \"Paul Rogalski\"],\n    \"createDate\": \"2024-09-30\",\n    \"lastModifyDate\": \"2024-09-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_409499_428047_512677_512675_v5_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_led_pot_12x1w_qcl_rgb_ww_428047.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i5958p8_yd59vq8a.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [168, 172, 130],\n    \"weight\": 0.42,\n    \"power\": 17,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 1W QCL-LEDs (RGBWW)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 01\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [17, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 02\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 03\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 04\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 05\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [85, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 06\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 07\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [119, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 08\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 09\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [153, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [187, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [204, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"No Function / Color Presets / Sound Control\": \"Sound Control\"\n          }\n        }\n      ]\n    },\n    \"No Function\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blackout\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ff9600\"]\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ffb400\"]\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff008c\"]\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff8080\"]\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#8080ff\"]\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#ffc828\"]\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Sound Control\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound program selection\",\n        \"soundControlled\": true\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Program\",\n        \"No Function / Color Presets / Sound Control\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/picobeam-30-quad-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PicoBeam 30 Quad LED\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-11-27\",\n    \"lastModifyDate\": \"2019-11-27\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/372682_c_372682_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/de/fun_generation_picobeam_30_quad_led.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de//vidiot/02591c1c/video_i4648p8_yd59vq8a.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [172, 235, 174],\n    \"weight\": 3,\n    \"power\": 46,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"30W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 4]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"All white\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 233],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 236],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [237, 249],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-Channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-Channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Program\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"13-Channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Program\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/picobeam-60-cob-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PicoBeam 60 COB RGBW\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"gloryfire\"],\n    \"createDate\": \"2019-11-27\",\n    \"lastModifyDate\": \"2019-11-27\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/442853_c_442853_v2_r1_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/de/fun_generation_picobeam_60_cob_rgbw.htm\"\n    ],\n    \"video\": [\n      \"https://www.thomann.de/de/thomanntv_video_fun_generation_picobeam_60_cob_rgbw_7286.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [147, 234, 175],\n    \"weight\": 3,\n    \"power\": 65,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"60W RGBW COB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 4]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"200deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"All white\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark\",\n          \"colors\": [\"#aaaaaa\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 233],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 236],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [237, 249],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-Channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-Channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Program\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"13-Channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Program\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/picoblade-fx-4x10w-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PicoBlade FX 4x10W RGBW\",\n  \"categories\": [\"Moving Head\", \"Strobe\", \"Color Changer\", \"Dimmer\", \"Flower\"],\n  \"meta\": {\n    \"authors\": [\"Raimund\"],\n    \"createDate\": \"2019-07-18\",\n    \"lastModifyDate\": \"2019-07-18\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/432322_c_432322_en_online.pdf\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i6951p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [160, 250, 150],\n    \"weight\": 3,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4× 10W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 4]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Lenses Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [192, 222],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [223, 224],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Master\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"All white\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 233],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 236],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [237, 249],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Motor Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Lenses Rotation\",\n        \"Master\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Lenses Rotation\",\n        \"Master\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Motor Speed\",\n        \"Lenses Rotation\",\n        \"Master\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/picospot-20-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PicoSpot 20 LED\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"LordVonAdel\", \"Moritz Weirauch\"],\n    \"createDate\": \"2019-08-21\",\n    \"lastModifyDate\": \"2024-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/372642_c_372642_r3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_picospot_20_led.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de//vidiot/02591c1c/video_i4640p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [162, 242, 174],\n    \"weight\": 3,\n    \"power\": 35,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12W white CREE LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff9900\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"200deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [22, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [33, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [44, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [55, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [66, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [77, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [88, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [99, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [110, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [121, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [132, 142],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [143, 153],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [154, 164],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [165, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [176, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 46],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [47, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [63, 78],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [79, 93],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [94, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [125, 140],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 156],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [157, 171],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [172, 187],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [188, 203],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [204, 218],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [219, 249],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 02 (empty)\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 03 (empty)\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 04 (empty)\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 05 (empty)\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 06 (empty)\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 07 (empty)\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 08 (empty)\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 09 (empty)\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 1\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 2\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 3\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 4\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 5\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 6\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 7\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 8 (empty)\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 9 (empty)\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Empty\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Empty\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled operation\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Program\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/picospot-45-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PicoSpot 45 LED\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"Peter Käning\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-08-21\",\n    \"lastModifyDate\": \"2023-02-05\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/424284_c_424284_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_picospot_45_led.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [162, 242, 174],\n    \"weight\": 3,\n    \"power\": 70,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"45W white CREE LED\",\n      \"lumens\": 400,\n      \"colorTemperature\": 8000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff9900\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"200deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [22, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [33, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [44, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [55, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [66, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [77, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [88, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [99, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [110, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [121, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [132, 142],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [143, 153],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [154, 164],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [165, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [176, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 124],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [125, 140],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 156],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [157, 172],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [173, 188],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [189, 204],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [205, 220],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 236],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [237, 249],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 02 (empty)\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 03 (empty)\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 04 (empty)\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 05 (empty)\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 06 (empty)\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 07 (empty)\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 08 (empty)\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scene 09 (empty)\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 1\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 2\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 3\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 4\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 5\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 6\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 7\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 8 (empty)\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Programme 9 (empty)\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Empty\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Empty\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled operation\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Program\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/picowash-40-pixel-quad-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PicoWash 40 Pixel Quad LED\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Harm Aldick\"],\n    \"createDate\": \"2019-05-13\",\n    \"lastModifyDate\": \"2019-05-13\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2019-05-11\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.2 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/372705_c_372705_v2_r1_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_picowash_40_pixel_quad_led.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [162, 228, 174],\n    \"weight\": 2.8,\n    \"power\": 55,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4x 10W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [28, 28]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"LED 1\", \"LED 2\"],\n        [\"LED 3\", \"LED 4\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Motor Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"All White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [230, 233],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 236],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [237, 249],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Motor Speed\",\n        \"Master Dimmer\",\n        \"Function\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Motor Speed\",\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Function\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"25-channel\",\n      \"shortName\": \"25ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Motor Speed\",\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red LED 1\",\n        \"Green LED 1\",\n        \"Blue LED 1\",\n        \"White LED 1\",\n        \"Red LED 2\",\n        \"Green LED 2\",\n        \"Blue LED 2\",\n        \"White LED 2\",\n        \"Red LED 3\",\n        \"Green LED 3\",\n        \"Blue LED 3\",\n        \"White LED 3\",\n        \"Red LED 4\",\n        \"Green LED 4\",\n        \"Blue LED 4\",\n        \"White LED 4\",\n        \"Function\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/separ-hex-led-rgbaw-uv.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SePar Hex LED RGBAW UV\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"Christian Kuster\"],\n    \"createDate\": \"2022-04-11\",\n    \"lastModifyDate\": \"2022-04-11\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2022-04-07\",\n      \"comment\": \"created by OFL – https://open-fixture-library.org/fun-generation/separ-quad-led-rgbw (version 1.3.0)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_440827_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_separ_hex_led_rgbaw_uv_ir.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i7285p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 175, 115],\n    \"weight\": 1.1,\n    \"power\": 21,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 8W RGBAW UV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 1\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 2\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 3\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 4\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 5\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 6\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 7\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 8\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 9\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [135, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 10\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 11\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [165, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 12\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 13\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [195, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 14\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 15\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Automatic show 16\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Music-controlled show\",\n          \"switchChannels\": {\n            \"Speed / Color Presets / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blackout\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [15, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [30, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [45, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [60, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [75, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Amber\",\n          \"colors\": [\"#ff5f00\"]\n        },\n        {\n          \"dmxRange\": [120, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + 82% Green\",\n          \"colors\": [\"#ffd900\"]\n        },\n        {\n          \"dmxRange\": [135, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + UV\",\n          \"colors\": [\"#ff0000\", \"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + 27% Blue + 27% UV\",\n          \"colors\": [\"#ff0043\", \"#321d3c\"]\n        },\n        {\n          \"dmxRange\": [165, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [180, 194],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + 66% White\",\n          \"colors\": [\"#e08585\"]\n        },\n        {\n          \"dmxRange\": [195, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + 66% White\",\n          \"colors\": [\"#85e085\"]\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + 66% White\",\n          \"colors\": [\"#8585e0\"]\n        },\n        {\n          \"dmxRange\": [225, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + 70% Green + 50% White + Amber\",\n          \"colors\": [\"#eec03a\"]\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White + Amber + UV\",\n          \"colors\": [\"#ebc247\", \"#8800ff\"]\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Program\",\n        \"Speed / Color Presets / Sound Sensitivity\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/separ-quad-led-rgb-uv.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SePar Quad LED RGB UV\",\n  \"shortName\": \"FunGenSeParRGBUV\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\", \"Felix Edelmann\"],\n    \"createDate\": \"2019-05-04\",\n    \"lastModifyDate\": \"2019-05-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/399604_c_399539_399604_r4_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_separ_quad_led_rgb_uv_ir.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=t4v9gRd8nZI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [228, 227, 112],\n    \"weight\": 1.1,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 4W RGBUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"Are the DMX values for this capability correct?\"\n        }\n      ]\n    },\n    \"Colors / Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fawn\",\n          \"colors\": [\"#e5aa70\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff99dd\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light red\",\n          \"colors\": [\"#ffaaaa\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light green\",\n          \"colors\": [\"#aaffaa\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\",\n          \"colors\": [\"#aaaaff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold white\",\n          \"colors\": [\"#ddeeff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm white\",\n          \"colors\": [\"#ffeedd\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 6\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 7\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 8\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 9\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 10\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 11\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 12\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music-controlled show\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Colors / Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Colors / Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/fun-generation/separ-quad-led-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SePar Quad LED RGBW\",\n  \"shortName\": \"FunGenSeParRGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-05-04\",\n    \"lastModifyDate\": \"2019-05-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/399539_c_399539_399604_r4_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/fun_generation_separ_quad_led_rgbw_ir.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=p6xEum0o_jA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [228, 227, 112],\n    \"weight\": 1.1,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x 4W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"Are the DMX values for this capability correct?\"\n        }\n      ]\n    },\n    \"Colors / Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fawn\",\n          \"colors\": [\"#e5aa70\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff99dd\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light red\",\n          \"colors\": [\"#ffaaaa\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light green\",\n          \"colors\": [\"#aaffaa\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\",\n          \"colors\": [\"#aaaaff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold white\",\n          \"colors\": [\"#ddeeff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm white\",\n          \"colors\": [\"#ffeedd\"],\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 6\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 7\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 8\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 9\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 10\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 11\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic show 12\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music-controlled show\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Colors / Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Intensity\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Colors / Programs\",\n        \"Program Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/futurelight/dj-scan-250.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DJ-Scan 250\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Max Jöhnk\"],\n    \"createDate\": \"2021-09-14\",\n    \"lastModifyDate\": \"2021-09-14\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/55802/Future-Light-Dj-Scan-250.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=8GOpwwclPAc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [525, 300, 150],\n    \"weight\": 15,\n    \"power\": 500,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark blue\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light green\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cherry red\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [19, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [36, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [54, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [72, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [90, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [108, 126],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [16, 135],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [136, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [6, 128],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [200, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Shutter / Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/futurelight/dmh-75-i-led-moving-head.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DMH-75.i LED Moving Head\",\n  \"shortName\": \"FuturelightDMH75i\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-12-12\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51841840-MANUAL-1.10-de-en_00087817.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=oMMej19YziM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [299, 398, 252],\n    \"weight\": 8.5,\n    \"power\": 115,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"72W white LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 18]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Pan / Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Pan / Tilt function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Normal\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at Pan / Tilt movement\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan rotation forwards\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan rotation backwards\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt rotation forwards\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt rotation backwards\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan / Tilt rotation forwards\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan / Tilt rotation backwards\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan rotation forwards, Tilt rotation backwards\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan rotation backwards, Tilt rotation forwards\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter / Strobe function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Normal shutter function\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [64, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 223],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Shutter / Strobe basic\": {\n      \"name\": \"Shutter / Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Pulse effect in sequences\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color wheel function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Normal color change\",\n          \"switchChannels\": {\n            \"Color wheel\": \"Color wheel: Color selection\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at color change\",\n          \"switchChannels\": {\n            \"Color wheel\": \"Color wheel: Color selection\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speed\": \"fast CW\",\n          \"switchChannels\": {\n            \"Color wheel\": \"Color wheel speed CW\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speed\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Color wheel\": \"Color wheel speed CCW\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color change at every position\",\n          \"switchChannels\": {\n            \"Color wheel\": \"Color wheel position\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 111],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"switchChannels\": {\n            \"Color wheel\": \"Color wheel: Color selection\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color wheel\": \"Color wheel: Color selection\"\n          }\n        }\n      ]\n    },\n    \"Color wheel: Color selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 27],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [28, 55],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [56, 83],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [84, 111],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [112, 139],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [140, 167],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [168, 195],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [196, 223],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9\n        }\n      ]\n    },\n    \"Color wheel speed CW\": {\n      \"capability\": {\n        \"type\": \"WheelRotation\",\n        \"wheel\": \"Color Wheel\",\n        \"speedStart\": \"slow CW\",\n        \"speedEnd\": \"fast CW\"\n      }\n    },\n    \"Color wheel speed CCW\": {\n      \"capability\": {\n        \"type\": \"WheelRotation\",\n        \"wheel\": \"Color Wheel\",\n        \"speedStart\": \"slow CCW\",\n        \"speedEnd\": \"fast CCW\"\n      }\n    },\n    \"Color wheel position\": {\n      \"capability\": {\n        \"type\": \"WheelRotation\",\n        \"wheel\": \"Color Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Color wheel basic\": {\n      \"name\": \"Color wheel\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 11],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [12, 17],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [18, 23],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [24, 29],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [30, 35],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [36, 41],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [42, 47],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [48, 53],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [54, 59],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [60, 65],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [66, 71],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [72, 77],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [78, 83],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [84, 89],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [90, 95],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [102, 106],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9,\n          \"comment\": \"blackout at color change\"\n        },\n        {\n          \"dmxRange\": [107, 119],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [120, 132],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [133, 145],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [146, 158],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [159, 171],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [172, 184],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [185, 197],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [198, 210],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [211, 223],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"comment\": \"Forwards rainbow effect\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"comment\": \"Backwards rainbow effect\"\n        }\n      ]\n    },\n    \"Gobo wheel function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Normal gobo change\",\n          \"switchChannels\": {\n            \"Gobo wheel\": \"Gobo wheel: Gobo selection\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at gobo change\",\n          \"switchChannels\": {\n            \"Gobo wheel\": \"Gobo wheel: Gobo selection\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotating gobo wheel forwards\",\n          \"switchChannels\": {\n            \"Gobo wheel\": \"Gobo wheel speed CW\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotating gobo wheel backwards\",\n          \"switchChannels\": {\n            \"Gobo wheel\": \"Gobo wheel speed CCW\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo change at every position\",\n          \"switchChannels\": {\n            \"Gobo wheel\": \"Gobo wheel position\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"switchChannels\": {\n            \"Gobo wheel\": \"Gobo wheel: Gobo selection\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Gobo wheel\": \"Gobo wheel: Gobo selection\"\n          }\n        }\n      ]\n    },\n    \"Gobo wheel: Gobo selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8\n        }\n      ]\n    },\n    \"Gobo wheel speed CW\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo wheel speed CCW\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo wheel position\": {\n      \"capability\": {\n        \"type\": \"WheelRotation\",\n        \"wheel\": \"Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo wheel basic\": {\n      \"name\": \"Gobo wheel\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 11],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [12, 17],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [18, 23],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [24, 29],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [30, 35],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [36, 41],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [42, 47],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [48, 53],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1,\n          \"comment\": \"blackout at gobo change\"\n        },\n        {\n          \"dmxRange\": [54, 59],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2,\n          \"comment\": \"blackout at gobo change\"\n        },\n        {\n          \"dmxRange\": [60, 65],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3,\n          \"comment\": \"blackout at gobo change\"\n        },\n        {\n          \"dmxRange\": [66, 71],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4,\n          \"comment\": \"blackout at gobo change\"\n        },\n        {\n          \"dmxRange\": [72, 77],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5,\n          \"comment\": \"blackout at gobo change\"\n        },\n        {\n          \"dmxRange\": [78, 83],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6,\n          \"comment\": \"blackout at gobo change\"\n        },\n        {\n          \"dmxRange\": [84, 89],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7,\n          \"comment\": \"blackout at gobo change\"\n        },\n        {\n          \"dmxRange\": [90, 95],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8,\n          \"comment\": \"blackout at gobo change\"\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"This capability is not documented in the manual.\"\n        },\n        {\n          \"dmxRange\": [98, 115],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [116, 133],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [134, 151],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [152, 169],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [170, 187],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [188, 205],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [206, 223],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [225, 239],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo rotation function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo indexing\",\n          \"switchChannels\": {\n            \"Gobo rotation\": \"Gobo indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotating gobo wheel forwards\",\n          \"switchChannels\": {\n            \"Gobo rotation\": \"Gobo rotation speed CW\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotating gobo wheel backwards\",\n          \"switchChannels\": {\n            \"Gobo rotation\": \"Gobo rotation speed CCW\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro forwards\",\n          \"switchChannels\": {\n            \"Gobo rotation\": \"Motion macro speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro forwards with blackout\",\n          \"switchChannels\": {\n            \"Gobo rotation\": \"Motion macro speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro backwards\",\n          \"switchChannels\": {\n            \"Gobo rotation\": \"Motion macro speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro backwards with blackout\",\n          \"switchChannels\": {\n            \"Gobo rotation\": \"Motion macro speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Gobo rotation\": \"Gobo indexing\"\n          }\n        }\n      ]\n    },\n    \"Gobo indexing\": {\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo rotation speed CW\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo rotation speed CCW\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Motion macro speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Gobo rotation basic\": {\n      \"name\": \"Gobo rotation\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro forwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Motion macro backwards\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [225, 239],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 127],\n          \"type\": \"Prism\",\n          \"speedStart\": \"stop\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\",\n          \"speedStart\": \"stop\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Reset, display control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all motors\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan / Tilt\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset colors\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset other motors\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display off\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display on\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Hibernation\"\n        },\n        {\n          \"dmxRange\": [96, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan / Tilt Speed\",\n        \"Pan / Tilt function\",\n        \"Shutter / Strobe function\",\n        \"Shutter / Strobe\",\n        \"Dimmer intensity\",\n        \"Color wheel function\",\n        \"Color wheel\",\n        \"Gobo wheel function\",\n        \"Gobo wheel\",\n        \"Gobo rotation function\",\n        \"Gobo rotation\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset, display control\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan / Tilt Speed\",\n        \"Pan / Tilt function\",\n        \"Shutter / Strobe function\",\n        \"Shutter / Strobe\",\n        \"Dimmer intensity\",\n        \"Color wheel function\",\n        \"Color wheel\",\n        \"Gobo wheel function\",\n        \"Gobo wheel\",\n        \"Gobo rotation function\",\n        \"Gobo rotation\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset, display control\"\n      ]\n    },\n    {\n      \"name\": \"Basic 8 bit\",\n      \"shortName\": \"bas8bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan / Tilt Speed\",\n        \"Pan / Tilt function\",\n        \"Shutter / Strobe basic\",\n        \"Dimmer intensity\",\n        \"Color wheel basic\",\n        \"Gobo wheel basic\",\n        \"Gobo rotation basic\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset, display control\"\n      ]\n    },\n    {\n      \"name\": \"Basic 16 bit\",\n      \"shortName\": \"bas16bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan / Tilt Speed\",\n        \"Pan / Tilt function\",\n        \"Shutter / Strobe basic\",\n        \"Dimmer intensity\",\n        \"Color wheel basic\",\n        \"Gobo wheel basic\",\n        \"Gobo rotation basic\",\n        \"Prism\",\n        \"Focus\",\n        \"Reset, display control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/futurelight/pro-slim-par-7-hcl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PRO Slim PAR-7 HCL\",\n  \"shortName\": \"PROSlim7HCL\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-05-11\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51842547-MANUAL-1.10-de-en_00094623.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Aql4Q-Rqs_g\",\n      \"https://www.youtube.com/watch?v=QisBVTgeS9o\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [253, 259.8, 98],\n    \"weight\": 3.3,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [23, 23]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"],\n          \"comment\": \"Red 100% / Green increasing / Blue 0%\"\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"Red decreasing / Green 100% / Blue 0%\"\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"],\n          \"comment\": \"Red 0% / Green 100% / Blue increasing\"\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Red 0% / Green decreasing / Blue 100%\"\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"],\n          \"comment\": \"Red increasing / Green 0% / Blue 100%\"\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"],\n          \"comment\": \"Red 100% / Green 0% / Blue decreasing\"\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"],\n          \"comment\": \"Red 100% / Green increasing / Blue increasing\"\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Red decreasing / Green decreasing / Blue 100%\"\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red 100% / Green 100% / Blue 100% / White 100%\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"White 1\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbe87\"],\n          \"colorTemperature\": \"3400K\",\n          \"comment\": \"White 2\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd3af\"],\n          \"colorTemperature\": \"4200K\",\n          \"comment\": \"White 3\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffe2ca\"],\n          \"colorTemperature\": \"4900K\",\n          \"comment\": \"White 4\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"colorTemperature\": \"5600K\",\n          \"comment\": \"White 5\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fff4ea\"],\n          \"colorTemperature\": \"5900K\",\n          \"comment\": \"White 6\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffefa\"],\n          \"colorTemperature\": \"6500K\",\n          \"comment\": \"White 7\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#edefff\"],\n          \"colorTemperature\": \"7200K\",\n          \"comment\": \"White 8\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dde6ff\"],\n          \"colorTemperature\": \"8000K\",\n          \"comment\": \"White 9\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d7e2ff\"],\n          \"colorTemperature\": \"8500K\",\n          \"comment\": \"White 10\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cadaff\"],\n          \"colorTemperature\": \"10000K\",\n          \"comment\": \"White 11\"\n        }\n      ]\n    },\n    \"Internal Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [241, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mic Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use Control Board setting dimmer speed\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"instant\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": 1\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": 2\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": 3\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Value / Brightness\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Strobe\",\n        \"Color Presets\",\n        \"Internal Programs\",\n        \"Program Speed / Mic Sensitivity\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"HSV\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Value / Brightness\"\n      ]\n    },\n    {\n      \"name\": \"HSI\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/futurelight/sc-250-scanner.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SC-250 Scanner\",\n  \"shortName\": \"FuturelightSC250\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-12-21\",\n    \"lastModifyDate\": \"2019-05-17\"\n  },\n  \"comment\": \"Note that the manual contains some mistakes that are corrected in this definition.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.de/manual/317298/Future-Light-Sc-250.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=OkrkEscJLDI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [280, 160, 470],\n    \"weight\": 11.1,\n    \"power\": 250,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"HIT 150 W\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [19, 19]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lightgreen\",\n          \"colors\": [\"#90ee90\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lightblue\",\n          \"colors\": [\"#66ccff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffaaaa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#7f1ae5\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red-Blue\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow-Green\",\n          \"colors\": [\"#ffff00\", \"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lightblue-Magenta\",\n          \"colors\": [\"#66ccff\", \"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"comment\": \"Rainbow Effect\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"comment\": \"Rainbow Effect\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [24, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [48, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [80, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [104, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [128, 151],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [152, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [176, 207],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [208, 231],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        }\n      ]\n    },\n    \"Gobo Indexing / Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"0%\",\n          \"brightnessEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"8Hz\"\n        },\n        {\n          \"dmxRange\": [128, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"in sequences\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"in sequences\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Indexing / Rotation\",\n        \"Shutter / Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/futurelight/stb-648-led-strobe-smd-5050.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"STB-648 LED Strobe SMD 5050\",\n  \"categories\": [\"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-03\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://media.steinigke.de/documents_t/51841370-MANUAL-1.00-de-en_00068855.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=M_syNbUd4iY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [420, 225, 165],\n    \"weight\": 4.5,\n    \"power\": 160,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"648x SMD 5050 LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Brightness\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Strobe\",\n        \"Brightness\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/galaxis/g-flame.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"G-Flame\",\n  \"shortName\": \"g-flame\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"William Tessier\"],\n    \"createDate\": \"2023-10-15\",\n    \"lastModifyDate\": \"2023-10-15\"\n  },\n  \"comment\": \"Very versatile flame effect device due to various control inputs: DMX, 12-24V, ext. contact, radio and RS485\\n\\nNote that this fixture listens to two channels that don't need to be adjacent, so they are represented by different modes here.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.firing-system.com/wp-content/uploads/User-Manual-G-Flame-V2.43-036.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.firing-system.com/project/g-flame/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=8wesqf4VVOQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [300, 300, 350],\n    \"weight\": 10.5,\n    \"DMXconnector\": \"5-pin XLR IP65\"\n  },\n  \"availableChannels\": {\n    \"Flame\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 228],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Flame Off\"\n        },\n        {\n          \"dmxRange\": [229, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flame On\",\n          \"comment\": \"when Safety is off\"\n        }\n      ]\n    },\n    \"Safety\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety ON\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety OFF\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Flame Channel\",\n      \"shortName\": \"flame\",\n      \"channels\": [\n        \"Flame\"\n      ]\n    },\n    {\n      \"name\": \"Safety Channel\",\n      \"shortName\": \"safety\",\n      \"channels\": [\n        \"Safety\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/gantom/precision-dmx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Precision DMX\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Brian McDade\"],\n    \"createDate\": \"2020-03-28\",\n    \"lastModifyDate\": \"2020-03-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.gantom.com/wp-content/uploads/2018/07/Precision-DMX-User-Guide-1.1.pdf\",\n      \"https://www.gantom.com/wp-content/uploads/2018/05/Precision_DMX_2018.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Oi_wBNiZeQk\"\n    ]\n  },\n  \"helpWanted\": \"Does the 3ch mode really exist? It is never mentioned in the manual.\",\n  \"physical\": {\n    \"dimensions\": [44.5, 52.5, 52],\n    \"power\": 3.8,\n    \"DMXconnector\": \"3.5mm stereo jack\",\n    \"bulb\": {\n      \"type\": \"RGB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [21, 21]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"At which DMX value can which color be selected?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Built-in Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 31],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"What does this capability do? Is channel 5 really set to 'Effect Speed', and which speed is controlled then?\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 71],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 111],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 151],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 231],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"red, green, blue\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 250],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6-color\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Candle Flicker\",\n          \"switchChannels\": {\n            \"Strobe / Effect Speed\": \"Effect Speed\"\n          }\n        }\n      ]\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe / Effect Speed\",\n        \"Built-in Functions\",\n        \"Master Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/4-channel-dimmer-pack.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"4-Channel Dimmer Pack\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Goetz\"],\n    \"createDate\": \"2021-06-17\",\n    \"lastModifyDate\": \"2021-06-17\"\n  },\n  \"comment\": \"Your usual off-the-shelf generic 4 Channel Dimmer Pack from Botec, Stairville, Lightmaxx, EuroLite, ShowTex, Varytec etc.\",\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": [\"1\", \"2\"],\n      \"3/4\": [\"3\", \"4\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer Master\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer 1/2\",\n        \"Dimmer 3/4\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer 1\",\n        \"Dimmer 2\",\n        \"Dimmer 3\",\n        \"Dimmer 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/cmy-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"CMY Fader\",\n  \"shortName\": \"CMY\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-12-12\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"availableChannels\": {\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\", \"Cyan fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"fineChannelAliases\": [\"Magenta fine\", \"Magenta fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"fineChannelAliases\": [\"Yellow fine\", \"Yellow fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Cyan fine^2\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Magenta fine^2\",\n        \"Yellow\",\n        \"Yellow fine\",\n        \"Yellow fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/color-temperature-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Color Temperature Fader\",\n  \"categories\": [\"Other\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2024-05-13\",\n    \"lastModifyDate\": \"2024-05-13\"\n  },\n  \"comment\": \"Generic fader + color temperature\",\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"fineChannelAliases\": [\"Intensity fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"warm\",\n        \"colorTemperatureEnd\": \"cold\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Intensity\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Intensity\",\n        \"Intensity fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/cw-ww-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"CW/WW Fader\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"sonarkon\"],\n    \"createDate\": \"2019-06-23\",\n    \"lastModifyDate\": \"2019-06-23\"\n  },\n  \"availableChannels\": {\n    \"Warm White\": {\n      \"fineChannelAliases\": [\"Warm White fine\", \"Warm White fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"Cold White\": {\n      \"fineChannelAliases\": [\"Cold White fine\", \"Cold White fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cold White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit W/C\",\n      \"shortName\": \"8bit-wc\",\n      \"channels\": [\n        \"Warm White\",\n        \"Cold White\"\n      ]\n    },\n    {\n      \"name\": \"8 bit C/W\",\n      \"shortName\": \"8bit-cw\",\n      \"channels\": [\n        \"Cold White\",\n        \"Warm White\"\n      ]\n    },\n    {\n      \"name\": \"16 bit W/C\",\n      \"shortName\": \"16bit-wc\",\n      \"channels\": [\n        \"Warm White\",\n        \"Warm White fine\",\n        \"Cold White\",\n        \"Cold White fine\"\n      ]\n    },\n    {\n      \"name\": \"16 bit C/W\",\n      \"shortName\": \"16bit-cw\",\n      \"channels\": [\n        \"Cold White\",\n        \"Cold White fine\",\n        \"Warm White\",\n        \"Warm White fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit W/C\",\n      \"shortName\": \"24bit-wc\",\n      \"channels\": [\n        \"Warm White\",\n        \"Warm White fine\",\n        \"Warm White fine^2\",\n        \"Cold White\",\n        \"Cold White fine\",\n        \"Cold White fine^2\"\n      ]\n    },\n    {\n      \"name\": \"24 bit C/W\",\n      \"shortName\": \"24bit-cw\",\n      \"channels\": [\n        \"Cold White\",\n        \"Cold White fine\",\n        \"Cold White fine^2\",\n        \"Warm White\",\n        \"Warm White fine\",\n        \"Warm White fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/desk-channel.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Desk Channel\",\n  \"shortName\": \"DeskCh\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-07-17\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"fineChannelAliases\": [\"Intensity fine\", \"Intensity fine^2\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Intensity\",\n        \"Intensity fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Intensity\",\n        \"Intensity fine\",\n        \"Intensity fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/drgb-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DRGB Fader\",\n  \"shortName\": \"DRGB\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-12-07\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\", \"Dimmer fine^2\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\", \"Red fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\", \"Green fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\", \"Blue fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"16 bit Dimmer\",\n      \"shortName\": \"16bit-dimmer\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit Dimmer\",\n      \"shortName\": \"24bit-dimmer\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimmer fine^2\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimmer fine^2\",\n        \"Red\",\n        \"Red fine\",\n        \"Red fine^2\",\n        \"Green\",\n        \"Green fine\",\n        \"Green fine^2\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Blue fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/drgbw-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DRGBW Fader\",\n  \"shortName\": \"DRGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"ameisso\"],\n    \"createDate\": \"2018-02-15\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\", \"Dimmer fine^2\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\", \"Red fine^2\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\", \"Green fine^2\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\", \"Blue fine^2\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\", \"White fine^2\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"16 bit Dimmer\",\n      \"shortName\": \"16bit-dimmer\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit Dimmer\",\n      \"shortName\": \"24bit-dimmer\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimmer fine^2\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimmer fine^2\",\n        \"Red\",\n        \"Red fine\",\n        \"Red fine^2\",\n        \"Green\",\n        \"Green fine\",\n        \"Green fine^2\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Blue fine^2\",\n        \"White\",\n        \"White fine\",\n        \"White fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/grbw-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"GRBW Fader\",\n  \"shortName\": \"GRBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Stuart Hanlon\"],\n    \"createDate\": \"2020-04-17\",\n    \"lastModifyDate\": \"2020-04-17\"\n  },\n  \"comment\": \"RGBW fixture with GRBW pixel order\",\n  \"availableChannels\": {\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\", \"Green fine^2\"],\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\", \"Red fine^2\"],\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\", \"Blue fine^2\"],\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\", \"White fine^2\"],\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Green\",\n        \"Red\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Green\",\n        \"Green fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Green\",\n        \"Green fine\",\n        \"Green fine^2\",\n        \"Red\",\n        \"Red fine\",\n        \"Red fine^2\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Blue fine^2\",\n        \"White\",\n        \"White fine\",\n        \"White fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/pan-tilt.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Pan/Tilt Fader\",\n  \"shortName\": \"PanTilt\",\n  \"categories\": [\"Moving Head\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-07-17\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\", \"Pan fine^2\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\", \"Tilt fine^2\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\"\n      ]\n    },\n    {\n      \"name\": \"16 bit (alternate)\",\n      \"shortName\": \"16bit-alt\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Pan fine^2\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Tilt fine^2\"\n      ]\n    },\n    {\n      \"name\": \"24 bit (alternate)\",\n      \"shortName\": \"24bit-alt\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan fine^2\",\n        \"Tilt fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/rgb-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RGB Fader\",\n  \"shortName\": \"RGB\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-07-17\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\", \"Red fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\", \"Green fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\", \"Blue fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Red fine^2\",\n        \"Green\",\n        \"Green fine\",\n        \"Green fine^2\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Blue fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/rgba-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RGBA Fader\",\n  \"shortName\": \"RGBA\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-12-12\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\", \"Red fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\", \"Green fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\", \"Blue fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"fineChannelAliases\": [\"Amber fine\", \"Amber fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Amber\",\n        \"Amber fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Red fine^2\",\n        \"Green\",\n        \"Green fine\",\n        \"Green fine^2\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Blue fine^2\",\n        \"Amber\",\n        \"Amber fine\",\n        \"Amber fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/rgbd-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RGBD Fader\",\n  \"shortName\": \"RGBD\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-12-07\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\", \"Red fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\", \"Green fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\", \"Blue fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\", \"Dimmer fine^2\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"16 bit Dimmer\",\n      \"shortName\": \"16bit-dimmer\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit Dimmer\",\n      \"shortName\": \"24bit-dimmer\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimmer fine^2\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Red fine^2\",\n        \"Green\",\n        \"Green fine\",\n        \"Green fine^2\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Blue fine^2\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Dimmer fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/rgbw-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RGBW Fader\",\n  \"shortName\": \"RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-12-07\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\", \"Red fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\", \"Green fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\", \"Blue fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\", \"White fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"24 bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Red fine^2\",\n        \"Green\",\n        \"Green fine\",\n        \"Green fine^2\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Blue fine^2\",\n        \"White\",\n        \"White fine\",\n        \"White fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/rgbwauv-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RGBWAUV Fader\",\n  \"shortName\": \"RGBWAUV\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Shuichi\", \"Flo Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2021-09-19\",\n    \"lastModifyDate\": \"2023-04-20\"\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"fineChannelAliases\": [\"Amber fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"fineChannelAliases\": [\"UV fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"16 bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Amber\",\n        \"Amber fine\",\n        \"UV\",\n        \"UV fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/rgbww-fader.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RGBWW Fader\",\n  \"shortName\": \"RGBWW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"ameisso\"],\n    \"createDate\": \"2019-01-21\",\n    \"lastModifyDate\": \"2019-01-21\"\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\", \"Red fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\", \"Green fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\", \"Blue fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Warm White\": {\n      \"fineChannelAliases\": [\"Warm White fine\", \"Warm White fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"Cold White\": {\n      \"fineChannelAliases\": [\"Cold White fine\", \"Cold White fine^2\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cold White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Warm White\",\n        \"Cold White\"\n      ]\n    },\n    {\n      \"name\": \"16 Bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Warm White\",\n        \"Warm White fine\",\n        \"Cold White\",\n        \"Cold White fine\"\n      ]\n    },\n    {\n      \"name\": \"24 Bit\",\n      \"shortName\": \"24bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Red fine^2\",\n        \"Green\",\n        \"Green fine\",\n        \"Green fine^2\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Blue fine^2\",\n        \"Warm White\",\n        \"Warm White fine\",\n        \"Warm White fine^2\",\n        \"Cold White\",\n        \"Cold White fine\",\n        \"Cold White fine^2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/generic/strobe.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Strobe\",\n  \"categories\": [\"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Mikey Rowlands\"],\n    \"createDate\": \"2019-11-01\",\n    \"lastModifyDate\": \"2019-11-01\"\n  },\n  \"availableChannels\": {\n    \"Frequency\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Frequency + Dimmer\",\n      \"channels\": [\n        \"Frequency\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Dimmer + Frequency\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Frequency\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ghost/ip-spot-bat.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"IP Spot Bat\",\n  \"shortName\": \"GhostIPSBat\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"zampano\"],\n    \"createDate\": \"2018-05-30\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"comment\": \"Mode 2\",\n  \"links\": {\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_nbH55XYGYU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [240, 165, 210],\n    \"weight\": 3,\n    \"power\": 72,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"6x12W RGWAUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"10Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 predefined colors\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"ColorPulse\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Master Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ghost/ip-spot-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"IP Spot Pro\",\n  \"shortName\": \"GhostIPSPro\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"zampano\"],\n    \"createDate\": \"2019-08-08\",\n    \"lastModifyDate\": \"2019-08-08\"\n  },\n  \"physical\": {\n    \"dimensions\": [340, 240, 240],\n    \"weight\": 4.5,\n    \"power\": 200,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"15W RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Function macro\",\n          \"helpWanted\": \"Which macros can be selected at which DMX values? Or is there only one macro from 1…255?\"\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Strobe\",\n        \"Macros\",\n        \"Macro Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glp/force-120.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Force 120\",\n  \"shortName\": \"GLPForce120\",\n  \"categories\": [\"Fan\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-12-04\",\n    \"lastModifyDate\": \"2018-12-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://glp.de/files/products/force-120-product-data/Force_120_1.5_en-us.pdf\"\n    ],\n    \"productPage\": [\n      \"https://glp.de/en/products/stage-effects-root/stage-effects/force-120-en\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=b2354sK3VaQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1400, 1400, 400],\n    \"weight\": 94,\n    \"power\": 1000,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"T1\", \"T2\", \"T3\"],\n        [\"C1\", \"C2\", \"C3\"],\n        [\"B1\", \"B2\", \"B3\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Top\": [\"T1\", \"T2\", \"T3\"],\n      \"Center\": [\"C1\", \"C2\", \"C3\"],\n      \"Bottom\": [\"B1\", \"B2\", \"B3\"],\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Fan Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [4, 128],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"30rpm\",\n          \"speedEnd\": \"750rpm\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [133, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"-30rpm\",\n          \"speedEnd\": \"-750rpm\"\n        }\n      ]\n    },\n    \"LED Intensity Master\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 47],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [48, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 111],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [112, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [144, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"with blackout pause\"\n        },\n        {\n          \"dmxRange\": [200, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Idle\"\n        },\n        {\n          \"dmxRange\": [51, 64],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [65, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 194],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 582,\n          \"parameterEnd\": 618,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM frequency (Hertz)\"\n        },\n        {\n          \"dmxRange\": [195, 197],\n          \"type\": \"Maintenance\",\n          \"parameter\": 1200,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM frequency (Hertz)\"\n        },\n        {\n          \"dmxRange\": [198, 200],\n          \"type\": \"Maintenance\",\n          \"parameter\": 2400,\n          \"hold\": \"3s\",\n          \"comment\": \"PWM frequency (Hertz)\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Braking Delay on\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Braking Delay off\"\n        },\n        {\n          \"dmxRange\": [221, 247],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset all functions\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Color Presets $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm Yellow\",\n          \"colors\": [\"#ffcc00\"]\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#00ffcc\"]\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#dd00ff\"]\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff88cc\"]\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Fan Speed\",\n        \"LED Intensity Master\",\n        \"Shutter\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Top\", \"Center\", \"Bottom\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Color Presets $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Normal\",\n      \"shortName\": \"norm\",\n      \"channels\": [\n        \"Fan Speed\",\n        \"LED Intensity Master\",\n        \"Shutter\",\n        \"Control\",\n        \"Color Presets Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"Extended Legacy\",\n      \"shortName\": \"extleg\",\n      \"channels\": [\n        \"Fan Speed\",\n        \"LED Intensity Master\",\n        \"Shutter\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Top\", \"Center\", \"Bottom\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Color Presets $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Normal Legacy\",\n      \"shortName\": \"normleg\",\n      \"channels\": [\n        \"Fan Speed\",\n        \"LED Intensity Master\",\n        \"Shutter\",\n        \"Color Presets Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glp/impression-fr1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"impression FR1\",\n  \"shortName\": \"GLPFR1\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-11-26\",\n    \"lastModifyDate\": \"2019-05-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://glp.de/files/products/impression-fr1-product-data/GLP_impression_FR1_User_Manual_EN_Rev_G_20201208.pdf\"\n    ],\n    \"productPage\": [\n      \"https://glp.de/en/products/entertainment-lighting/moving-lights/impression-fr1-en\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=m7rz8ALXmkc\",\n      \"https://www.youtube.com/watch?v=zP2-DSfA1y4\",\n      \"https://www.youtube.com/watch?v=OobOrRDEdDo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [190, 355, 140],\n    \"weight\": 4,\n    \"power\": 80,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"Osram Ostar RGBW LED\"\n    },\n    \"lens\": {\n      \"name\": \"Micro-Fresnel\",\n      \"degreesMinMax\": [3.7, 35]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"220deg\"\n      }\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#00ffbb\"]\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#e6e6fa\"]\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#e0b0ff\"]\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"CTO\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"CTB\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random colors\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 47],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [48, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 111],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [112, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [144, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"blackout pause\"\n        },\n        {\n          \"dmxRange\": [200, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"14Hz\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CTC\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"10000K\",\n        \"colorTemperatureEnd\": \"2500K\"\n      }\n    },\n    \"Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 38],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [39, 41],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer curve extra-soft\"\n        },\n        {\n          \"dmxRange\": [42, 44],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer curve soft\"\n        },\n        {\n          \"dmxRange\": [45, 47],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer curve linear\"\n        },\n        {\n          \"dmxRange\": [48, 56],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [57, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display auto-off\"\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display permanently on\"\n        },\n        {\n          \"dmxRange\": [63, 65],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display invert off\"\n        },\n        {\n          \"dmxRange\": [66, 68],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display invert on\"\n        },\n        {\n          \"dmxRange\": [69, 71],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX: Blackout\"\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX: Hold current effect\"\n        },\n        {\n          \"dmxRange\": [78, 86],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [87, 89],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fans temperature-regulated\"\n        },\n        {\n          \"dmxRange\": [90, 92],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fans constant high\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fans constant medium\"\n        },\n        {\n          \"dmxRange\": [96, 98],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fans constant low\"\n        },\n        {\n          \"dmxRange\": [99, 104],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [105, 107],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"P/T position feedback off\"\n        },\n        {\n          \"dmxRange\": [108, 110],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"P/T position feedback on\"\n        },\n        {\n          \"dmxRange\": [111, 116],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [117, 119],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Tilt invert off\"\n        },\n        {\n          \"dmxRange\": [120, 122],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Tilt invert on\"\n        },\n        {\n          \"dmxRange\": [123, 125],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pan invert off\"\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pan invert on\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Zoom invert off\"\n        },\n        {\n          \"dmxRange\": [132, 134],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Zoom invert off\"\n        },\n        {\n          \"dmxRange\": [135, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 186],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 582,\n          \"parameterEnd\": 618,\n          \"hold\": \"5s\",\n          \"comment\": \"PWM frequency (Hz)\"\n        },\n        {\n          \"dmxRange\": [187, 191],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [192, 194],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM frequency 1200Hz\"\n        },\n        {\n          \"dmxRange\": [195, 197],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM frequency 2400Hz\"\n        },\n        {\n          \"dmxRange\": [198, 200],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM frequency 4800Hz\"\n        },\n        {\n          \"dmxRange\": [201, 203],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM frequency 9600Hz\"\n        },\n        {\n          \"dmxRange\": [204, 251],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset entire fixture\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"35deg\",\n        \"angleEnd\": \"3.7deg\"\n      }\n    },\n    \"Pan Continuous\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 254],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"PanContinuous\",\n          \"speed\": \"stop\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Normal\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Presets\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CTC\",\n        \"Settings\",\n        \"Zoom\",\n        \"Pan Continuous\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glp/impression-laser.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"impression Laser\",\n  \"shortName\": \"GLPLaser\",\n  \"categories\": [\"Laser\", \"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2018-02-02\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"comment\": \"The manual leaves gaps between capabilities, which are corrected here.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.glp.de/de/produkte?format=raw&task=download&fid=65\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=xtjhMXGvLiE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [340, 145, 370],\n    \"weight\": 7.5,\n    \"power\": 170,\n    \"powerConnectors\": {\n      \"powerCON\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"660deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"300deg\"\n      }\n    },\n    \"Access\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Basic range (8ch)\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard range (12ch)\"\n        },\n        {\n          \"dmxRange\": [160, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Extended range (16ch)\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Full range (20ch)\"\n        }\n      ]\n    },\n    \"Folder\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 8\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Page 9\"\n        }\n      ]\n    },\n    \"File\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 32],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [33, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 1\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 2\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 3\"\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 4\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 5\"\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 6\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 7\"\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 8\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 9\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 10\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 11\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 12\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 13\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 14\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 15\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 16\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 17\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 18\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 19\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 20\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 21\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 22\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 23\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 24\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 25\"\n        },\n        {\n          \"dmxRange\": [133, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 26\"\n        },\n        {\n          \"dmxRange\": [137, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 27\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 28\"\n        },\n        {\n          \"dmxRange\": [145, 148],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 29\"\n        },\n        {\n          \"dmxRange\": [149, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 30\"\n        },\n        {\n          \"dmxRange\": [153, 156],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 31\"\n        },\n        {\n          \"dmxRange\": [157, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 32\"\n        },\n        {\n          \"dmxRange\": [161, 164],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 33\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 34\"\n        },\n        {\n          \"dmxRange\": [169, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 35\"\n        },\n        {\n          \"dmxRange\": [173, 176],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 36\"\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 37\"\n        },\n        {\n          \"dmxRange\": [181, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 38\"\n        },\n        {\n          \"dmxRange\": [185, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 39\"\n        },\n        {\n          \"dmxRange\": [189, 192],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 40\"\n        },\n        {\n          \"dmxRange\": [193, 196],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 41\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 42\"\n        },\n        {\n          \"dmxRange\": [201, 204],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 43\"\n        },\n        {\n          \"dmxRange\": [205, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 44\"\n        },\n        {\n          \"dmxRange\": [209, 212],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 45\"\n        },\n        {\n          \"dmxRange\": [213, 216],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 46\"\n        },\n        {\n          \"dmxRange\": [217, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 47\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cue 48\"\n        }\n      ]\n    },\n    \"Playback Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"100%\",\n          \"comment\": \"Normal speed\"\n        },\n        {\n          \"dmxRange\": [17, 32],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [33, 127],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"25%\",\n          \"speedEnd\": \"99%\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"100%\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"101%\",\n          \"speedEnd\": \"200%\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\",\n        \"helpWanted\": \"Is this the correct direction?\"\n      }\n    },\n    \"X Size\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BeamAngle\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"40deg\"\n      }\n    },\n    \"Y Size\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BeamAngle\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"40deg\"\n      }\n    },\n    \"Rotation\": {\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"X Position\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"BeamPosition\",\n        \"horizontalAngleStart\": \"0deg\",\n        \"horizontalAngleEnd\": \"40deg\"\n      }\n    },\n    \"Y Position\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"BeamPosition\",\n        \"verticalAngleStart\": \"0deg\",\n        \"verticalAngleEnd\": \"40deg\"\n      }\n    },\n    \"Visible Points\": {\n      \"defaultValue\": 255,\n      \"capability\": {\n        \"type\": \"Maintenance\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\",\n        \"comment\": \"Visible points\"\n      }\n    },\n    \"Scan Rate\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Maintenance\",\n          \"parameter\": 30000,\n          \"comment\": \"Default Scan Rate\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 6000,\n          \"parameterEnd\": 30000,\n          \"comment\": \"Scan Rate\"\n        }\n      ]\n    },\n    \"Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 42],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [43, 53],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaa00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [54, 75],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [76, 86],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#66ff00\"],\n          \"comment\": \"Lime\"\n        },\n        {\n          \"dmxRange\": [87, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00dd00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [110, 163],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [164, 189],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [190, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbbaa\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [221, 228],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [229, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Release\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Hold\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Loop\"\n        },\n        {\n          \"dmxRange\": [160, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Next\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stop\"\n        }\n      ]\n    },\n    \"Reserved\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Normal\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Access\",\n        \"Folder\",\n        \"File\",\n        \"Playback Speed\",\n        \"Intensity\",\n        \"Zoom\",\n        \"X Size\",\n        \"Y Size\",\n        \"Rotation\",\n        \"X Position\",\n        \"Y Position\",\n        \"Visible Points\",\n        \"Scan Rate\",\n        \"Release\",\n        \"Color\",\n        \"Reserved\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glp/impression-spot-one.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"impression Spot One\",\n  \"shortName\": \"GLPSpotOne\",\n  \"categories\": [\"Color Changer\", \"Moving Head\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-10-12\",\n    \"lastModifyDate\": \"2019-05-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://glp.de/files/products/impression-spot-one-product-data/Impression_SpotOne_Manual_V1.97_EN.PDF\"\n    ],\n    \"productPage\": [\n      \"https://glp.de/en/products/discontinued/impression-spot-one-en\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=5b4GN_JgW2c\",\n      \"https://www.youtube.com/watch?v=PXzqRswF7js\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 0,\n    \"softwareVersion\": \"8804\"\n  },\n  \"physical\": {\n    \"dimensions\": [472, 618, 230],\n    \"weight\": 23,\n    \"power\": 700,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"400W RGB LED Chipset\"\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"4 Circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Vertical Bars\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Two Light Tunnels\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Triangles Random\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Dash Mini\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Dots Medium\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Starry Night Dense\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Cone\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Leaves Foliage\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Teeth\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Shreds\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Angry Hurricane\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Shredded Earth\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Diamond Pattern\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"660deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"280deg\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No macro (use RGB channels)\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9900\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffcc00\"],\n          \"comment\": \"Yellow warm\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffcc\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dd00ff\"],\n          \"comment\": \"Malve\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00aa\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff88cc\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White CTO\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White CTB\",\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 47],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [48, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 111],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [160, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"0.1s\",\n          \"comment\": \"Strobe effect pause\"\n        },\n        {\n          \"dmxRange\": [200, 241],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [242, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No correction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"7200K\",\n          \"colorTemperatureEnd\": \"3200K\"\n        }\n      ]\n    },\n    \"Gobo Shake & Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Gobo Shake off\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"12.5%\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"25%\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"37.5%\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"62.5%\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"75%\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"87.5%\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"100%\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"12.5%\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"25%\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"37.5%\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"62.5%\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"75%\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"87.5%\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"100%\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"WheelShake\",\n          \"wheel\": [\"Gobo Wheel 1\", \"Gobo Wheel 2\"],\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"12.5%\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"WheelShake\",\n          \"wheel\": [\"Gobo Wheel 1\", \"Gobo Wheel 2\"],\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"25%\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"WheelShake\",\n          \"wheel\": [\"Gobo Wheel 1\", \"Gobo Wheel 2\"],\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"37.5%\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"WheelShake\",\n          \"wheel\": [\"Gobo Wheel 1\", \"Gobo Wheel 2\"],\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"WheelShake\",\n          \"wheel\": [\"Gobo Wheel 1\", \"Gobo Wheel 2\"],\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"62.5%\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"WheelShake\",\n          \"wheel\": [\"Gobo Wheel 1\", \"Gobo Wheel 2\"],\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"75%\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"WheelShake\",\n          \"wheel\": [\"Gobo Wheel 1\", \"Gobo Wheel 2\"],\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"87.5%\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"WheelShake\",\n          \"wheel\": [\"Gobo Wheel 1\", \"Gobo Wheel 2\"],\n          \"shakeAngleStart\": \"12.5%\",\n          \"shakeAngleEnd\": \"100%\",\n          \"shakeSpeed\": \"100%\"\n        },\n        {\n          \"dmxRange\": [208, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 253],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset head\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all functions\"\n        }\n      ]\n    },\n    \"Movement\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No movement\"\n        },\n        {\n          \"dmxRange\": [1, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan size 1 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan size 2 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan size 3 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan size 4 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt size 1 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt size 2 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt size 3 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilt size 4 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt size 1 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt size 2 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt size 3 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt size 4 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt inverse size 1 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt inverse size 2 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt inverse size 3 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt inverse size 4 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle size 1 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle size 2 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle size 3 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle size 4 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle inverse size 1 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle inverse size 2 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle inverse size 3 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle inverse size 4 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Eight size 1 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Eight size 2 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Eight size 3 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Eight size 4 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random size 1 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random size 2 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random size 3 phase 0…270°\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random size 4 phase 0…270°\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Generic\",\n          \"comment\": \"Pan/Tilt relative movement\",\n          \"helpWanted\": \"What does this capability do?\"\n        },\n        {\n          \"dmxRange\": [2, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"10deg\",\n        \"angleEnd\": \"32deg\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Gobo Wheel 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 126],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 192],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo 1 Position\": {\n      \"fineChannelAliases\": [\"Gobo 1 Position fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [193, 253],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 126],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 192],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo 2 Position\": {\n      \"fineChannelAliases\": [\"Gobo 2 Position fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [193, 253],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Effect Wheel Swing\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Motion Wheel Swing\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"Effect Wheel Position\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"helpWanted\": \"Does this capability go from DMX value 0 to 1 or just 0?\"\n        },\n        {\n          \"dmxRange\": [1, 128],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [129, 254],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"helpWanted\": \"Does this capability go from DMX value 254 or just 255 to 255?\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Prism swing out\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Prism\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 192],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Prism\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"fineChannelAliases\": [\"Iris fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 131],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"100%\",\n          \"openPercentEnd\": \"4%\"\n        },\n        {\n          \"dmxRange\": [132, 255],\n          \"type\": \"Iris\",\n          \"openPercent\": \"4%\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Normal 24-channel\",\n      \"shortName\": \"normal-24ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Macros\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Gobo Shake & Reset\",\n        \"Movement\",\n        \"Pan/Tilt Speed\",\n        \"Zoom\",\n        \"Focus\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 Position\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 Position\",\n        \"Effect Wheel Swing\",\n        \"Effect Wheel Position\",\n        \"Prism\",\n        \"Iris\"\n      ]\n    },\n    {\n      \"name\": \"Compress 20-channel\",\n      \"shortName\": \"compress-20ch\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Macros\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Focus\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 Position\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 Position\",\n        \"Effect Wheel Swing\",\n        \"Effect Wheel Position\",\n        \"Prism\",\n        \"Iris\"\n      ]\n    },\n    {\n      \"name\": \"Extended 31-channel\",\n      \"shortName\": \"extended-31ch\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Macros\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Gobo Shake & Reset\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 Position\",\n        \"Gobo 1 Position fine\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 Position\",\n        \"Gobo 2 Position fine\",\n        \"Effect Wheel Swing\",\n        \"Effect Wheel Position\",\n        \"Prism\",\n        \"Iris\",\n        \"Iris fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glp/impression-x4-bar-10.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Impression X4 Bar 10\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Rummels Bucht Berlin\"],\n    \"createDate\": \"2018-05-26\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"comment\": \"impression X4 BAR 10 DMX chart (v1.6) from software version: v0.60\",\n  \"links\": {\n    \"manual\": [\n      \"https://glp.de/files/products/impression-x4-bar-10-product-data/impression_X4_Bar_10_Manual_v1.8_EN.pdf\"\n    ],\n    \"productPage\": [\n      \"https://glp.de/en/products/entertainment-lighting/moving-lights/impression-x4-bar-10-en\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=cMRGfFBBzg0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [500, 240, 100],\n    \"weight\": 8,\n    \"power\": 200,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"Osram Ostar RGBW multi-chip LED\",\n      \"colorTemperature\": 10000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 50]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [10, 1, 1],\n    \"pixelGroups\": {\n      \"1 & 2\": [\"1\", \"2\"],\n      \"3 & 4\": [\"3\", \"4\"],\n      \"5 & 6\": [\"5\", \"6\"],\n      \"7 & 8\": [\"7\", \"8\"],\n      \"9 & 10\": [\"9\", \"10\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"210deg\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"50deg\",\n        \"angleEnd\": \"7deg\"\n      }\n    },\n    \"CTO\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No CTO\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"default\",\n          \"colorTemperatureEnd\": \"CTO\"\n        }\n      ]\n    },\n    \"Set 1 Color\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Colors adjustable via RGB\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f6cd8b\"],\n          \"comment\": \"Warm Yellow\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b24662\"],\n          \"comment\": \"Malve\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"comment\": \"White - CTO\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#edefff\"],\n          \"comment\": \"White - CTB\",\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Random colors\"\n        }\n      ]\n    },\n    \"Set 1 Red\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Set 1 Green\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Set 1 Blue\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Set 1 White\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Set 1 Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 47],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [48, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 111],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [112, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [144, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"0.1s\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [200, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"fineChannelAliases\": [\"Intensity fine\"],\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Special\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"Maintenance\",\n          \"comment\": \"no mirror\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"mirror color priority\"\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"Maintenance\",\n          \"comment\": \"mirror color mixing\"\n        },\n        {\n          \"dmxRange\": [12, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt slow mode off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt slow mode on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt current off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt current on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt reset off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt reset on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Flip off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Flip on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Mode DPixH (HiRes)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Mode SPixH (HiRes)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Mode High Resolution\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Mode Normal\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Mode Compressed\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Mode DPix\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Mode SPix\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve ESoft\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve Soft\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Curve Lin\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"Maintenance\",\n          \"comment\": \"X4 Compatibility off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"X4 Compatibility on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent-Mode off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent-Mode on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Position Feedback off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Position Feedback on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX hold off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX hold on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt inverse off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt inverse on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pixel inverse off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pixel inverse on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom inverse off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom inverse on\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fixture default\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fixture reset\",\n          \"hold\": \"3s\"\n        }\n      ]\n    },\n    \"Set 2 Color\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Colors adjustable via RGB\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f6cd8b\"],\n          \"comment\": \"Warm Yellow\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b24662\"],\n          \"comment\": \"Malve\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"comment\": \"White - CTO\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#edefff\"],\n          \"comment\": \"White - CTB\",\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Random colors\"\n        }\n      ]\n    },\n    \"Set 2 Red\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Set 2 Green\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Set 2 Blue\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Set 2 White\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Set 2 Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Set 3 Color\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Colors adjustable via RGB\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f6cd8b\"],\n          \"comment\": \"Warm Yellow\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6e6fa\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b24662\"],\n          \"comment\": \"Malve\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"comment\": \"White - CTO\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#edefff\"],\n          \"comment\": \"White - CTB\",\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Random colors\"\n        }\n      ]\n    },\n    \"Set 3 Red\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Set 3 Green\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Set 3 Blue\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Set 3 White\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Set 3 Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Crossfade\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"0s\",\n        \"durationEnd\": \"2s\",\n        \"comment\": \"Transition time\"\n      }\n    },\n    \"Star Effect\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Random internal shutter effect\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Set 1 Pattern Select\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"Set 1 Pattern Movement\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"Set 2 Pattern Select\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"Set 2 Pattern Movement\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"Pixel Select 1 - 8\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"Pixel Select 9 - 10\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Normal\",\n      \"shortName\": \"NORM\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Zoom\",\n        \"CTO\",\n        \"Set 1 Color\",\n        \"Set 1 Red\",\n        \"Set 1 Green\",\n        \"Set 1 Blue\",\n        \"Set 1 White\",\n        \"Set 1 Intensity\",\n        \"Shutter\",\n        \"Intensity\",\n        \"Special\",\n        \"Set 2 Color\",\n        \"Set 2 Red\",\n        \"Set 2 Green\",\n        \"Set 2 Blue\",\n        \"Set 2 White\",\n        \"Set 2 Intensity\",\n        \"Set 3 Color\",\n        \"Set 3 Red\",\n        \"Set 3 Green\",\n        \"Set 3 Blue\",\n        \"Set 3 White\",\n        \"Set 3 Intensity\",\n        \"Crossfade\",\n        \"Star Effect\",\n        \"Set 1 Pattern Select\",\n        \"Set 1 Pattern Movement\",\n        \"Set 2 Pattern Select\",\n        \"Set 2 Pattern Movement\",\n        \"Pixel Select 1 - 8\",\n        \"Pixel Select 9 - 10\"\n      ]\n    },\n    {\n      \"name\": \"Compressed\",\n      \"shortName\": \"COMP\",\n      \"channels\": [\n        null,\n        null,\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Set 1 Color\",\n        \"Set 1 Red\",\n        \"Set 1 Green\",\n        \"Set 1 Blue\",\n        \"Set 1 White\",\n        \"Shutter\",\n        \"Intensity\",\n        \"CTO\",\n        \"Special\",\n        \"Crossfade\",\n        \"Set 1 Pattern Movement\",\n        \"Zoom\",\n        \"Set 1 Pattern Select\",\n        \"Pixel Select 1 - 8\",\n        \"Pixel Select 9 - 10\"\n      ]\n    },\n    {\n      \"name\": \"High Resolution\",\n      \"shortName\": \"HIRES\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Zoom\",\n        \"CTO\",\n        \"Set 1 Color\",\n        \"Set 1 Red\",\n        \"Set 1 Green\",\n        \"Set 1 Blue\",\n        \"Set 1 White\",\n        \"Set 1 Intensity\",\n        \"Shutter\",\n        \"Intensity\",\n        \"Intensity fine\",\n        \"Special\",\n        \"Set 2 Color\",\n        \"Set 2 Red\",\n        \"Set 2 Green\",\n        \"Set 2 Blue\",\n        \"Set 2 White\",\n        \"Set 2 Intensity\",\n        \"Set 3 Color\",\n        \"Set 3 Red\",\n        \"Set 3 Green\",\n        \"Set 3 Blue\",\n        \"Set 3 White\",\n        \"Set 3 Intensity\",\n        \"Crossfade\",\n        \"Star Effect\",\n        \"Set 1 Pattern Select\",\n        \"Set 1 Pattern Movement\",\n        \"Set 2 Pattern Select\",\n        \"Set 2 Pattern Movement\",\n        \"Pixel Select 1 - 8\",\n        \"Pixel Select 9 - 10\"\n      ]\n    },\n    {\n      \"name\": \"Dual Pixel\",\n      \"shortName\": \"DPIX\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Shutter\",\n        \"Intensity\",\n        \"CTO\",\n        \"Special\",\n        \"Crossfade\",\n        \"Zoom\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelGroup\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Dual Pixel High Resolution\",\n      \"shortName\": \"DPIXH\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Shutter\",\n        \"Intensity\",\n        \"Intensity fine\",\n        \"CTO\",\n        \"Special\",\n        \"Crossfade\",\n        \"Zoom\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelGroup\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Single Pixel\",\n      \"shortName\": \"SPIX\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Shutter\",\n        \"Intensity\",\n        \"CTO\",\n        \"Special\",\n        \"Crossfade\",\n        \"Zoom\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Single Pixel High Resolution\",\n      \"shortName\": \"SPIXH\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Shutter\",\n        \"Intensity\",\n        \"Intensity fine\",\n        \"CTO\",\n        \"Special\",\n        \"Crossfade\",\n        \"Zoom\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glp/jdc1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"JDC1\",\n  \"categories\": [\"Strobe\", \"Blinder\", \"Matrix\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-06-14\",\n    \"lastModifyDate\": \"2019-12-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://glp.de/files/products/jdc1-product-data/GLP_JDC1_User_Manual_EN_Rev20240830-01.pdf\"\n    ],\n    \"productPage\": [\n      \"https://glp.de/en/products/entertainment-lighting/strobes/jdc1-en\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=fUEht-I-nZ4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [390, 284, 154],\n    \"weight\": 12,\n    \"power\": 1200,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"1320x Osram LRTB GVTG RGB LEDs, 216x CREE XP L LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [86, 148]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"C1a\", \"C1b\", \"C2a\", \"C2b\", \"C3a\", \"C3b\", \"C4a\", \"C4b\", \"C5a\", \"C5b\", \"C6a\", \"C6b\"],\n        [\"White 1\", \"White 2\", \"White 3\", \"White 4\", \"White 5\", \"White 6\", \"White 7\", \"White 8\", \"White 9\", \"White 10\", \"White 11\", \"White 12\"],\n        [\"C7a\", \"C7b\", \"C8a\", \"C8b\", \"C9a\", \"C9b\", \"C10a\", \"C10b\", \"C11a\", \"C11b\", \"C12a\", \"C12b\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Pixel 1\": [\"C1a\", \"C1b\"],\n      \"Pixel 2\": [\"C2a\", \"C2b\"],\n      \"Pixel 3\": [\"C3a\", \"C3b\"],\n      \"Pixel 4\": [\"C4a\", \"C4b\"],\n      \"Pixel 5\": [\"C5a\", \"C5b\"],\n      \"Pixel 6\": [\"C6a\", \"C6b\"],\n      \"Pixel 7\": [\"C7a\", \"C7b\"],\n      \"Pixel 8\": [\"C8a\", \"C8b\"],\n      \"Pixel 9\": [\"C9a\", \"C9b\"],\n      \"Pixel 10\": [\"C10a\", \"C10b\"],\n      \"Pixel 11\": [\"C11a\", \"C11b\"],\n      \"Pixel 12\": [\"C12a\", \"C12b\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"185deg\"\n      }\n    },\n    \"Beam Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Beam Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"7ms\",\n        \"durationEnd\": \"650ms\"\n      }\n    },\n    \"Beam Rate\": {\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"0.289Hz\",\n        \"speedEnd\": \"16.67Hz\"\n      }\n    },\n    \"Beam FX Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"comment\": \"Random white beam\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"comment\": \"Random single pixel of the white beam\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"flash over low light\"\n        },\n        {\n          \"dmxRange\": [77, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White beam, left to right\"\n        },\n        {\n          \"dmxRange\": [81, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White beam, left to right, random\"\n        },\n        {\n          \"dmxRange\": [85, 88],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White beam, right to left\"\n        },\n        {\n          \"dmxRange\": [89, 92],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White beam, right to left, random\"\n        },\n        {\n          \"dmxRange\": [93, 96],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White beam, left to right, bounce\"\n        },\n        {\n          \"dmxRange\": [97, 100],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White beam, left to right, bounce, random\"\n        },\n        {\n          \"dmxRange\": [101, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White beam, right to left, bounce\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White beam, right to left, bounce, random\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Zig, 6 steps\"\n        },\n        {\n          \"dmxRange\": [113, 116],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Zig, 6 steps, random\"\n        },\n        {\n          \"dmxRange\": [117, 120],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Zig, 6 steps, outer to center pixel\"\n        },\n        {\n          \"dmxRange\": [121, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Zig, 6 steps, outer to center pixel, random\"\n        },\n        {\n          \"dmxRange\": [125, 128],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Zigzag, 10 steps\"\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Zigzag, 10 steps, random\"\n        },\n        {\n          \"dmxRange\": [133, 179],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double flash\"\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double flash, random\"\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double flash, beam-color\"\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double flash, beam-color, random\"\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double flash, color-beam\"\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double flash, color-beam, random\"\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Triple flash\"\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Triple flash, random\"\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Triple flash, beam-color-beam\"\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Triple flash, beam-color-beam, random\"\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Triple flash, color-beam-color\"\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Triple flash, color-beam-color, random\"\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Quad flash\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Quad flash, random\"\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Quad flash, beam-color-beam-color\"\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Quad flash, beam-color-beam-color, random\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Quad flash, color-beam-color-beam\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Quad flash, color-beam-color-beam, random\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Special / Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 10°\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 20°\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 30°\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 40°\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 50°\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 60°\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 70°\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 80°\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 90°\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 100°\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 110°\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 120°\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 130°\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 140°\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 150°\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 160°\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 170°\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 180°\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 190°\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 200°\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 210°\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 220°\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 230°\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 240°\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 250°\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 260°\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 270°\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 280°\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 290°\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 300°\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 310°\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 320°\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 330°\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 340°\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 350°\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Channel 4-6 Offset 360°\"\n        },\n        {\n          \"dmxRange\": [37, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Position Feedback On\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Position Feedback Off\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"FX/Pattern Color Priority On\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"FX/Pattern Control Priority Off\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pixel H\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pixel V\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal Tilt Control\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse Tilt Control\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal Pixel Orientation\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse Pixel Orientation\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal Orientation, 2nd Pixel Line\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse Orientation, 2nd Pixel Line\"\n        },\n        {\n          \"dmxRange\": [100, 102],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 582Hz\"\n        },\n        {\n          \"dmxRange\": [103, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 583Hz\"\n        },\n        {\n          \"dmxRange\": [106, 107],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 584Hz\"\n        },\n        {\n          \"dmxRange\": [108, 110],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 585Hz\"\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 586Hz\"\n        },\n        {\n          \"dmxRange\": [113, 115],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 587Hz\"\n        },\n        {\n          \"dmxRange\": [116, 118],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 588Hz\"\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 589Hz\"\n        },\n        {\n          \"dmxRange\": [121, 123],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 590Hz\"\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 591Hz\"\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 592Hz\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 593Hz\"\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 594Hz\"\n        },\n        {\n          \"dmxRange\": [134, 136],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 595Hz\"\n        },\n        {\n          \"dmxRange\": [137, 138],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 596Hz\"\n        },\n        {\n          \"dmxRange\": [139, 141],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 597Hz\"\n        },\n        {\n          \"dmxRange\": [142, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 598Hz\"\n        },\n        {\n          \"dmxRange\": [145, 146],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 599Hz\"\n        },\n        {\n          \"dmxRange\": [147, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 600Hz\"\n        },\n        {\n          \"dmxRange\": [150, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 601Hz\"\n        },\n        {\n          \"dmxRange\": [152, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 602Hz\"\n        },\n        {\n          \"dmxRange\": [155, 157],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 603Hz\"\n        },\n        {\n          \"dmxRange\": [158, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 604Hz\"\n        },\n        {\n          \"dmxRange\": [160, 162],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 605Hz\"\n        },\n        {\n          \"dmxRange\": [163, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 606Hz\"\n        },\n        {\n          \"dmxRange\": [165, 167],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 607Hz\"\n        },\n        {\n          \"dmxRange\": [168, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 608Hz\"\n        },\n        {\n          \"dmxRange\": [171, 172],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 609Hz\"\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 610Hz\"\n        },\n        {\n          \"dmxRange\": [176, 177],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 611Hz\"\n        },\n        {\n          \"dmxRange\": [178, 180],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 612Hz\"\n        },\n        {\n          \"dmxRange\": [181, 183],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 613Hz\"\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 614Hz\"\n        },\n        {\n          \"dmxRange\": [186, 188],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 615Hz\"\n        },\n        {\n          \"dmxRange\": [189, 190],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 616Hz\"\n        },\n        {\n          \"dmxRange\": [191, 193],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 617Hz\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 618Hz\"\n        },\n        {\n          \"dmxRange\": [195, 197],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 1200Hz\"\n        },\n        {\n          \"dmxRange\": [198, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM Frequency 2400Hz\"\n        },\n        {\n          \"dmxRange\": [201, 209],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [210, 214],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Duration Percentage Mode On\"\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Duration Percentage Mode Off\"\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Flash On\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Flash Off\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"FX/Plate Color Priority On\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"FX/Plate Color Priority Off\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    },\n    \"Color Plate Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Flash Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"7ms\",\n        \"durationEnd\": \"650ms\"\n      }\n    },\n    \"Color Flash Rate\": {\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"0.289Hz\",\n        \"speedEnd\": \"16.67Hz\"\n      }\n    },\n    \"Color FX Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 10°\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 20°\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 30°\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 40°\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 50°\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 60°\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 70°\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 80°\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 90°\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 100°\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 110°\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 120°\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 130°\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 140°\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 150°\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 160°\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 170°\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 180°\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 190°\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 200°\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 210°\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 220°\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 230°\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 240°\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 250°\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 260°\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 270°\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 280°\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 290°\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 300°\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 310°\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 320°\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 330°\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 340°\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 350°\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Plate Offset 360°\"\n        },\n        {\n          \"dmxRange\": [37, 40],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Random white beam\"\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Random single pixel of the white beam\"\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"comment\": \"flash over low light\"\n        },\n        {\n          \"dmxRange\": [77, 179],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double flash\"\n        },\n        {\n          \"dmxRange\": [192, 203],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double flash, random\"\n        },\n        {\n          \"dmxRange\": [204, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Trriple flash\"\n        },\n        {\n          \"dmxRange\": [216, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Trriple flash, random\"\n        },\n        {\n          \"dmxRange\": [228, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Quad flash\"\n        },\n        {\n          \"dmxRange\": [240, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Quad flash, random\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No effect\"\n        }\n      ]\n    },\n    \"Plate Red Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Plate Green Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Plate Blue Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Plate White Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Set 2 Red Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Color Set 2 Green Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Color Set 2 Blue Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"FX Crossfade\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Pattern Color Movement\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Pattern Select Color\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Pattern Beam Movement\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Pattern Select Beam\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Color Set 2 Master Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Master Pix Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue Intensity\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Compressed Pro 14-channel\",\n      \"shortName\": \"M1\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Beam Intensity\",\n        \"Beam Duration\",\n        \"Beam Rate\",\n        \"Beam FX Shutter\",\n        \"Special / Control\",\n        \"Color Plate Intensity\",\n        \"Color Flash Duration\",\n        \"Color Flash Rate\",\n        \"Color FX Shutter\",\n        \"Plate Red Intensity\",\n        \"Plate Green Intensity\",\n        \"Plate Blue Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Normal 23-channel\",\n      \"shortName\": \"M2\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Beam Intensity\",\n        \"Beam Duration\",\n        \"Beam Rate\",\n        \"Beam FX Shutter\",\n        \"Special / Control\",\n        \"Color Plate Intensity\",\n        \"Color Flash Duration\",\n        \"Color Flash Rate\",\n        \"Color FX Shutter\",\n        \"Plate Red Intensity\",\n        \"Plate Green Intensity\",\n        \"Plate Blue Intensity\",\n        \"FX Crossfade\",\n        \"Pattern Color Movement\",\n        \"Pattern Select Color\",\n        \"Pattern Beam Movement\",\n        \"Pattern Select Beam\",\n        \"Color Set 2 Master Intensity\",\n        \"Color Set 2 Red Intensity\",\n        \"Color Set 2 Green Intensity\",\n        \"Color Set 2 Blue Intensity\"\n      ]\n    },\n    {\n      \"name\": \"SPix 68-channel\",\n      \"shortName\": \"M3\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Beam Intensity\",\n        \"Beam Duration\",\n        \"Beam Rate\",\n        \"Beam FX Shutter\",\n        \"Special / Control\",\n        \"Color Plate Intensity\",\n        \"Color Flash Duration\",\n        \"Color Flash Rate\",\n        \"Color FX Shutter\",\n        \"Plate Red Intensity\",\n        \"Plate Green Intensity\",\n        \"Plate Blue Intensity\",\n        \"FX Crossfade\",\n        \"Pattern Color Movement\",\n        \"Pattern Select Color\",\n        \"Pattern Beam Movement\",\n        \"Pattern Select Beam\",\n        \"Master Pix Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelGroup\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red Intensity\",\n            \"$pixelKey Green Intensity\",\n            \"$pixelKey Blue Intensity\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"White 1\",\n            \"White 2\",\n            \"White 3\",\n            \"White 4\",\n            \"White 5\",\n            \"White 6\",\n            \"White 7\",\n            \"White 8\",\n            \"White 9\",\n            \"White 10\",\n            \"White 11\",\n            \"White 12\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"SPix Pro 62-channel\",\n      \"shortName\": \"M4\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Beam Intensity\",\n        \"Beam Duration\",\n        \"Beam Rate\",\n        \"Beam FX Shutter\",\n        \"Special / Control\",\n        \"Color Plate Intensity\",\n        \"Color Flash Duration\",\n        \"Color Flash Rate\",\n        \"Color FX Shutter\",\n        \"Plate Red Intensity\",\n        \"Plate Green Intensity\",\n        \"Plate Blue Intensity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelGroup\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red Intensity\",\n            \"$pixelKey Green Intensity\",\n            \"$pixelKey Blue Intensity\"\n          ]\n        },\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"White 1\",\n            \"White 2\",\n            \"White 3\",\n            \"White 4\",\n            \"White 5\",\n            \"White 6\",\n            \"White 7\",\n            \"White 8\",\n            \"White 9\",\n            \"White 10\",\n            \"White 11\",\n            \"White 12\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"1Pix Pro 17-channel\",\n      \"shortName\": \"M5\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Beam Intensity\",\n        \"Beam Duration\",\n        \"Beam Rate\",\n        \"Beam FX Shutter\",\n        \"Special / Control\",\n        \"Color Plate Intensity\",\n        \"Color Flash Duration\",\n        \"Color Flash Rate\",\n        \"Color FX Shutter\",\n        \"Plate Red Intensity\",\n        \"Plate Green Intensity\",\n        \"Plate Blue Intensity\",\n        \"Color Set 2 Red Intensity\",\n        \"Color Set 2 Green Intensity\",\n        \"Color Set 2 Blue Intensity\"\n      ]\n    },\n    {\n      \"name\": \"Easy 11-channel\",\n      \"shortName\": \"M6\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Beam Intensity\",\n        \"Beam Duration\",\n        \"Beam Rate\",\n        \"Beam FX Shutter\",\n        \"Special / Control\",\n        \"Plate Red Intensity\",\n        \"Plate Green Intensity\",\n        \"Plate Blue Intensity\",\n        \"Plate White Intensity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glp/knv-arc.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"KNV Arc\",\n  \"categories\": [\"Effect\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-04-07\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://glp.de/files/products/knv-arc-product-data/KNV_CA_User_Manual_EN_Rev.B_SW_14.8_20190704.pdf\"\n    ],\n    \"productPage\": [\n      \"https://glp.de/en/products/entertainment-lighting/creative-led-system/knv-arc-en\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=JavZqUiT_ik\",\n      \"https://www.youtube.com/watch?v=ZlpA7hrJNSw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 250, 180],\n    \"weight\": 9.7,\n    \"power\": 800,\n    \"powerConnectors\": {\n      \"powerCON TRUE1\": \"input and output\"\n    },\n    \"bulb\": {\n      \"type\": \"25× 30W White LEDs, 400× 0.25W RGB LEDs\",\n      \"colorTemperature\": 5000,\n      \"lumens\": 55030\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null, null,  \"2\", null, null,  \"3\", null, null,  \"4\", null, null, null],\n        [ \"1\", null, null, null, null, null, null, null, null, null, null, null,  \"5\"],\n        [null, null, null,  \"7\", null, null,  \"8\", null, null,  \"9\", null, null, null],\n        [null,  \"6\", null, null, null, null, null, null, null, null, null, \"10\", null],\n        [null, null, null, null, \"12\", null, \"13\", null, \"14\", null, null, null, null],\n        [null, null, \"11\", null, null, null, null, null, null, null, \"15\", null, null],\n        [null, null, null, null, null, \"17\", \"18\", \"19\", null, null, null, null, null],\n        [null, null, null, \"16\", null, null, null, null, null, \"20\", null, null, null],\n        [null, null, null, null, null, \"22\", \"23\", \"24\", null, null, null, null, null],\n        [null, null, null, null, \"21\", null, null, null, \"25\", null, null, null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Row 1\": [ \"1\",  \"2\",  \"3\",  \"4\",  \"5\"],\n      \"Row 2\": [ \"6\",  \"7\",  \"8\",  \"9\", \"10\"],\n      \"Row 3\": [\"11\", \"12\", \"13\", \"14\", \"15\"],\n      \"Row 4\": [\"16\", \"17\", \"18\", \"19\", \"20\"],\n      \"Row 5\": [\"21\", \"22\", \"23\", \"24\", \"25\"],\n      \"White LEDs\": \"all\",\n      \"RGB LEDs\": \"all\",\n      \"Layer 1\": \"all\",\n      \"Layer 2\": \"all\",\n      \"Layer 3\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [5, 39],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [40, 74],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [75, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Double flash\"\n        },\n        {\n          \"dmxRange\": [145, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Random pixel\"\n        },\n        {\n          \"dmxRange\": [180, 214],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [215, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.289Hz\",\n          \"speedEnd\": \"16.67Hz\"\n        },\n        {\n          \"dmxRange\": [250, 252],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Hyperspeed\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Control / Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Idle\"\n        },\n        {\n          \"dmxRange\": [12, 38],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [39, 41],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Flash Off\"\n        },\n        {\n          \"dmxRange\": [42, 44],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Flash On\"\n        },\n        {\n          \"dmxRange\": [45, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 50],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimming curve Soft\"\n        },\n        {\n          \"dmxRange\": [51, 53],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimming curve Linear\"\n        },\n        {\n          \"dmxRange\": [54, 56],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [57, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Extra Shutter RGBW\"\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Extra Shutter RGB only\"\n        },\n        {\n          \"dmxRange\": [63, 65],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Extra Shutter White only\"\n        },\n        {\n          \"dmxRange\": [66, 68],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [69, 71],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fan mode regulated\"\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fan mode high\"\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fan mode medium\"\n        },\n        {\n          \"dmxRange\": [78, 80],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fan mode low\"\n        },\n        {\n          \"dmxRange\": [81, 83],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [84, 86],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display On\"\n        },\n        {\n          \"dmxRange\": [87, 89],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display Off\"\n        },\n        {\n          \"dmxRange\": [90, 92],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display Auto\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display invert Off\"\n        },\n        {\n          \"dmxRange\": [96, 98],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display invert On\"\n        },\n        {\n          \"dmxRange\": [99, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX = Capture scene\"\n        },\n        {\n          \"dmxRange\": [102, 104],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX = Stand-alone\"\n        },\n        {\n          \"dmxRange\": [105, 107],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX = Blackout\"\n        },\n        {\n          \"dmxRange\": [108, 110],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX = Hold\"\n        },\n        {\n          \"dmxRange\": [111, 113],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Test pattern On\"\n        },\n        {\n          \"dmxRange\": [114, 116],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Test pattern Off\"\n        },\n        {\n          \"dmxRange\": [117, 119],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Rotation Off\"\n        },\n        {\n          \"dmxRange\": [120, 122],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Rotation 90°\"\n        },\n        {\n          \"dmxRange\": [123, 125],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Rotation 180°\"\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Rotation 270°\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pixel mirror Off\"\n        },\n        {\n          \"dmxRange\": [132, 134],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pixel mirror On\"\n        },\n        {\n          \"dmxRange\": [135, 137],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation Off\"\n        },\n        {\n          \"dmxRange\": [138, 140],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 80%\"\n        },\n        {\n          \"dmxRange\": [141, 143],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 60%\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 40%\"\n        },\n        {\n          \"dmxRange\": [147, 149],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 20%\"\n        },\n        {\n          \"dmxRange\": [150, 152],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 10%\"\n        },\n        {\n          \"dmxRange\": [153, 158],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [159, 161],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation Off\"\n        },\n        {\n          \"dmxRange\": [162, 164],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 80%\"\n        },\n        {\n          \"dmxRange\": [165, 167],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 60%\"\n        },\n        {\n          \"dmxRange\": [168, 170],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 40%\"\n        },\n        {\n          \"dmxRange\": [171, 173],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 20%\"\n        },\n        {\n          \"dmxRange\": [174, 176],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 10%\"\n        },\n        {\n          \"dmxRange\": [177, 251],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reboot fixture\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red Pixel $pixelKey\": {\n      \"fineChannelAliases\": [\"Red Pixel $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green Pixel $pixelKey\": {\n      \"fineChannelAliases\": [\"Green Pixel $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue Pixel $pixelKey\": {\n      \"fineChannelAliases\": [\"Blue Pixel $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White Pixel $pixelKey\": {\n      \"fineChannelAliases\": [\"White Pixel $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Master\": {\n      \"fineChannelAliases\": [\"$pixelKey Master fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Transparent\"\n        },\n        {\n          \"dmxRange\": [2, 65535],\n          \"type\": \"Intensity\"\n        }\n      ]\n    },\n    \"$pixelKey Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"$pixelKey Flash Duration\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"7ms\",\n        \"durationEnd\": \"650ms\"\n      }\n    },\n    \"$pixelKey Flash Rate\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [2, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.289Hz\",\n          \"speedEnd\": \"16.67Hz\"\n        },\n        {\n          \"dmxRange\": [251, 252],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Hyperspeed\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Continuously on\"\n        }\n      ]\n    },\n    \"$pixelKey FX Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [2, 253],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"$pixelKey Flare Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flare effect\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flare effect\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"random\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flare effect\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"random pixel\"\n        },\n        {\n          \"dmxRange\": [170, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"$pixelKey FX Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\",\n          \"comment\": \"FX Off\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey Flash Rate\"\n          }\n        },\n        {\n          \"dmxRange\": [3, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sync strobe - circle mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [6, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sync strobe - 4 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [9, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sync strobe - 1 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random strobe - all\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random strobe - circle mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [18, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random strobe - 4 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random strobe - 1 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 26],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in/out - all\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [27, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in/out - circle mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in/out - 4 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [33, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in/out - 1 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Snake\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [39, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Raindrops\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random pixel\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random fake x 2\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random fake x 4\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Line\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double line\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [57, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Corner to corner line\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilted double lines\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [63, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilted double lines in to out\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"Center line running dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [69, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Middle line running dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer line running dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Corner to corner\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [78, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Arrow\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [84, 86],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wheel\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [87, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Half wheel\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circling dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer circle\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 98],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inner circle\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [99, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer 4 dots\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer single dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [105, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Middle single dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [108, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spinning 2x1 dots\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 113],\n          \"type\": \"Effect\",\n          \"effectName\": \"Asymmetrical 4 dots\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [114, 116],\n          \"type\": \"Effect\",\n          \"effectName\": \"Symmetrical 4 dots\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [117, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Square\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inside out\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [123, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inside out 2\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Effect\",\n          \"effectName\": \"Abstract 1\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Abstract 2\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [132, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Abstract 3\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [135, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hash tag\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [138, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flip flop\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Jumping slash\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Jumping 'L'\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [147, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Jumping pins\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Off - No Strobe or FX\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        }\n      ]\n    },\n    \"$pixelKey FX Crossfade Time\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [2, 127],\n          \"type\": \"EffectDuration\",\n          \"durationStart\": \"short\",\n          \"durationEnd\": \"long\",\n          \"comment\": \"Crossfade\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"EffectDuration\",\n          \"durationStart\": \"long\",\n          \"durationEnd\": \"short\",\n          \"comment\": \"Crossfade and tail\"\n        }\n      ]\n    },\n    \"$pixelKey Orientation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 90°\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 180°\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 270°\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Horizontal flip\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 90° & vertical flip\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 180° & horizontal flip\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 270° & vertical flip\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random rotate & flip\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random position\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 90° rotation & random position\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 180° rotation & random position\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 270° rotation & random position\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 90°\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 180°\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 270°\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate CCW at end\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate CW at end\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random rotate at end\"\n        },\n        {\n          \"dmxRange\": [115, 134],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 90° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 180° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 270° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Horizontal flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 90° & vertical flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 180° & horizontal flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 270° & vertical flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random Rotate & flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random position (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 90° rotation & random position (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 180° rotation & random position (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 270° rotation & random position (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [210, 214],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 90° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 180° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 270° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate CCW at end (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate CW at end (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random rotate at end (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        }\n      ]\n    },\n    \"$pixelKey FX Offset\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"$pixelKey FX Length\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"$pixelKey FX Color Generator\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random all pixels RGBCMY\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random single pixel RGBCMY\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random all pixels bright colors\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random single pixel bright colors\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red / Blue\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red / Green\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#00ff00\"],\n          \"comment\": \"Blue / Green\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\", \"#ff00ff\"],\n          \"comment\": \"Yellow / Magenta\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\", \"#00ffff\"],\n          \"comment\": \"Yellow / Cyan\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\", \"#ff00ff\"],\n          \"comment\": \"Cyan / Magenta\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\", \"#0000ff\"],\n          \"comment\": \"Yellow / Blue\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ff00ff\"],\n          \"comment\": \"Green / Magenta\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red / Green / Blue\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffff00\", \"#0000ff\"],\n          \"comment\": \"Red / Yellow / Blue\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffff00\", \"#ff00ff\", \"#00ffff\"],\n          \"comment\": \"Red / Green / Blue / Yellow / Magenta / Cyan\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red / Green / Blue - Horizontal line\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red / Green / Blue - Vertical line\"\n        },\n        {\n          \"dmxRange\": [180, 219],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite out\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"$pixelKey Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [5, 39],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [40, 74],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [75, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Double flash\"\n        },\n        {\n          \"dmxRange\": [145, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Pixel flare effect\"\n        },\n        {\n          \"dmxRange\": [180, 214],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [215, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.289Hz\",\n          \"speedEnd\": \"16.67Hz\"\n        },\n        {\n          \"dmxRange\": [250, 252],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Hyperspeed\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGBW 16-bit\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"White strobe with FX, RGB with FX\",\n      \"shortName\": \"23ch\",\n      \"channels\": [\n        \"White LEDs Dimmer\",\n        \"White LEDs Flash Duration\",\n        \"White LEDs Flash Rate / FX Speed\",\n        \"White LEDs Flare Effect\",\n        \"White LEDs FX Selection\",\n        \"White LEDs FX Crossfade Time\",\n        \"White LEDs Orientation\",\n        \"White LEDs FX Offset\",\n        \"White LEDs FX Length\",\n        \"RGB LEDs Dimmer\",\n        \"RGB LEDs Flash Duration\",\n        \"RGB LEDs Flash Rate / FX Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"RGB LEDs Flare Effect\",\n        \"RGB LEDs FX Selection\",\n        \"RGB LEDs FX Crossfade Time\",\n        \"RGB LEDs Orientation\",\n        \"RGB LEDs FX Offset\",\n        \"RGB LEDs FX Length\",\n        \"RGB LEDs FX Color Generator\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"RGB strobe with FX, White 25-pixel\",\n      \"shortName\": \"40ch\",\n      \"channels\": [\n        \"RGB LEDs Dimmer\",\n        \"RGB LEDs Flash Duration\",\n        \"RGB LEDs Flash Rate / FX Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"RGB LEDs Flare Effect\",\n        \"RGB LEDs FX Selection\",\n        \"RGB LEDs FX Crossfade Time\",\n        \"RGB LEDs Orientation\",\n        \"RGB LEDs FX Offset\",\n        \"RGB LEDs FX Length\",\n        \"RGB LEDs FX Color Generator\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"White Pixel $pixelKey\"\n          ]\n        },\n        \"White LEDs Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"White strobe with FX, RGB 25-pixel\",\n      \"shortName\": \"86ch\",\n      \"channels\": [\n        \"White LEDs Dimmer\",\n        \"White LEDs Flash Duration\",\n        \"White LEDs Flash Rate / FX Speed\",\n        \"White LEDs Flare Effect\",\n        \"White LEDs FX Selection\",\n        \"White LEDs FX Crossfade Time\",\n        \"White LEDs Orientation\",\n        \"White LEDs FX Offset\",\n        \"White LEDs FX Length\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red Pixel $pixelKey\",\n            \"Green Pixel $pixelKey\",\n            \"Blue Pixel $pixelKey\"\n          ]\n        },\n        \"RGB LEDs Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"Multi-layer RGBW with FX\",\n      \"shortName\": \"35ch\",\n      \"channels\": [\n        \"Layer 1 Red\",\n        \"Layer 1 Green\",\n        \"Layer 1 Blue\",\n        \"Layer 1 White\",\n        \"Layer 2 Master\",\n        \"Layer 2 Master fine\",\n        \"Layer 2 Flash Duration\",\n        \"Layer 2 Flash Rate / FX Speed\",\n        \"Layer 2 Flare Effect\",\n        \"Layer 2 Red\",\n        \"Layer 2 Green\",\n        \"Layer 2 Blue\",\n        \"Layer 2 White\",\n        \"Layer 2 FX Selection\",\n        \"Layer 2 FX Crossfade Time\",\n        \"Layer 2 Orientation\",\n        \"Layer 2 FX Offset\",\n        \"Layer 2 FX Length\",\n        \"Layer 2 FX Color Generator\",\n        \"Layer 3 Master\",\n        \"Layer 3 Master fine\",\n        \"Layer 3 Flash Duration\",\n        \"Layer 3 Flash Rate / FX Speed\",\n        \"Layer 3 Flare Effect\",\n        \"Layer 3 Red\",\n        \"Layer 3 Green\",\n        \"Layer 3 Blue\",\n        \"Layer 3 White\",\n        \"Layer 3 FX Selection\",\n        \"Layer 3 FX Crossfade Time\",\n        \"Layer 3 Orientation\",\n        \"Layer 3 FX Offset\",\n        \"Layer 3 FX Length\",\n        \"Layer 3 FX Color Generator\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 25-pixel 8-bit\",\n      \"shortName\": \"102ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red Pixel $pixelKey\",\n            \"Green Pixel $pixelKey\",\n            \"Blue Pixel $pixelKey\",\n            \"White Pixel $pixelKey\"\n          ]\n        },\n        \"Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 25-pixel 16-bit\",\n      \"shortName\": \"202ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red Pixel $pixelKey\",\n            \"Red Pixel $pixelKey fine\",\n            \"Green Pixel $pixelKey\",\n            \"Green Pixel $pixelKey fine\",\n            \"Blue Pixel $pixelKey\",\n            \"Blue Pixel $pixelKey fine\",\n            \"White Pixel $pixelKey\",\n            \"White Pixel $pixelKey fine\"\n          ]\n        },\n        \"Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glp/knv-cube.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"KNV Cube\",\n  \"categories\": [\"Matrix\", \"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2019-04-05\",\n    \"lastModifyDate\": \"2019-04-05\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://glp.de/files/products/knv-cube-product-data/KNV_CA_User_Manual_EN_Rev.B_SW_14.8_20190704.pdf\"\n    ],\n    \"productPage\": [\n      \"https://glp.de/en/products/entertainment-lighting/creative-led-system/knv-cube-en\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=JavZqUiT_ik\",\n      \"https://www.youtube.com/watch?v=ZlpA7hrJNSw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 250, 183],\n    \"weight\": 9.3,\n    \"power\": 800,\n    \"bulb\": {\n      \"type\": \"25× 30W White LEDs, 400× 0.25W RGB LEDs\",\n      \"colorTemperature\": 5000,\n      \"lumens\": 55030\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [ \"1\",  \"2\",  \"3\",  \"4\",  \"5\"],\n        [ \"6\",  \"7\",  \"8\",  \"9\", \"10\"],\n        [\"11\", \"12\", \"13\", \"14\", \"15\"],\n        [\"16\", \"17\", \"18\", \"19\", \"20\"],\n        [\"21\", \"22\", \"23\", \"24\", \"25\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"White LEDs\": \"all\",\n      \"RGB LEDs\": \"all\",\n      \"Layer 1\": \"all\",\n      \"Layer 2\": \"all\",\n      \"Layer 3\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [5, 39],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [40, 74],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [75, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Double flash\"\n        },\n        {\n          \"dmxRange\": [145, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Random pixel\"\n        },\n        {\n          \"dmxRange\": [180, 214],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [215, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.289Hz\",\n          \"speedEnd\": \"16.67Hz\"\n        },\n        {\n          \"dmxRange\": [250, 252],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Hyperspeed\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Control / Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Idle\"\n        },\n        {\n          \"dmxRange\": [12, 38],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [39, 41],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Flash Off\"\n        },\n        {\n          \"dmxRange\": [42, 44],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer Flash On\"\n        },\n        {\n          \"dmxRange\": [45, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 50],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimming curve Soft\"\n        },\n        {\n          \"dmxRange\": [51, 53],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimming curve Linear\"\n        },\n        {\n          \"dmxRange\": [54, 56],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [57, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Extra Shutter RGBW\"\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Extra Shutter RGB only\"\n        },\n        {\n          \"dmxRange\": [63, 65],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Extra Shutter White only\"\n        },\n        {\n          \"dmxRange\": [66, 68],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [69, 71],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fan mode regulated\"\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fan mode high\"\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fan mode medium\"\n        },\n        {\n          \"dmxRange\": [78, 80],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fan mode low\"\n        },\n        {\n          \"dmxRange\": [81, 83],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [84, 86],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display On\"\n        },\n        {\n          \"dmxRange\": [87, 89],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display Off\"\n        },\n        {\n          \"dmxRange\": [90, 92],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display Auto\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display invert Off\"\n        },\n        {\n          \"dmxRange\": [96, 98],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Display invert On\"\n        },\n        {\n          \"dmxRange\": [99, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX = Capture scene\"\n        },\n        {\n          \"dmxRange\": [102, 104],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX = Stand-alone\"\n        },\n        {\n          \"dmxRange\": [105, 107],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX = Blackout\"\n        },\n        {\n          \"dmxRange\": [108, 110],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"No DMX = Hold\"\n        },\n        {\n          \"dmxRange\": [111, 113],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Test pattern On\"\n        },\n        {\n          \"dmxRange\": [114, 116],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Test pattern Off\"\n        },\n        {\n          \"dmxRange\": [117, 119],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Rotation Off\"\n        },\n        {\n          \"dmxRange\": [120, 122],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Rotation 90°\"\n        },\n        {\n          \"dmxRange\": [123, 125],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Rotation 180°\"\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Rotation 270°\"\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pixel mirror Off\"\n        },\n        {\n          \"dmxRange\": [132, 134],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pixel mirror On\"\n        },\n        {\n          \"dmxRange\": [135, 137],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation Off\"\n        },\n        {\n          \"dmxRange\": [138, 140],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 80%\"\n        },\n        {\n          \"dmxRange\": [141, 143],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 60%\"\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 40%\"\n        },\n        {\n          \"dmxRange\": [147, 149],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 20%\"\n        },\n        {\n          \"dmxRange\": [150, 152],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"White output limitation 10%\"\n        },\n        {\n          \"dmxRange\": [153, 158],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [159, 161],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation Off\"\n        },\n        {\n          \"dmxRange\": [162, 164],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 80%\"\n        },\n        {\n          \"dmxRange\": [165, 167],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 60%\"\n        },\n        {\n          \"dmxRange\": [168, 170],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 40%\"\n        },\n        {\n          \"dmxRange\": [171, 173],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 20%\"\n        },\n        {\n          \"dmxRange\": [174, 176],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"RGB output limitation 10%\"\n        },\n        {\n          \"dmxRange\": [177, 251],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reboot fixture\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red Pixel $pixelKey\": {\n      \"fineChannelAliases\": [\"Red Pixel $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green Pixel $pixelKey\": {\n      \"fineChannelAliases\": [\"Green Pixel $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue Pixel $pixelKey\": {\n      \"fineChannelAliases\": [\"Blue Pixel $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White Pixel $pixelKey\": {\n      \"fineChannelAliases\": [\"White Pixel $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Master\": {\n      \"fineChannelAliases\": [\"$pixelKey Master fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Transparent\"\n        },\n        {\n          \"dmxRange\": [2, 65535],\n          \"type\": \"Intensity\"\n        }\n      ]\n    },\n    \"$pixelKey Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"$pixelKey Flash Duration\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"7ms\",\n        \"durationEnd\": \"650ms\"\n      }\n    },\n    \"$pixelKey Flash Rate\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [2, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.289Hz\",\n          \"speedEnd\": \"16.67Hz\"\n        },\n        {\n          \"dmxRange\": [251, 252],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Hyperspeed\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Continuously on\"\n        }\n      ]\n    },\n    \"$pixelKey FX Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [2, 253],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"$pixelKey Flare Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flare effect\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flare effect\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"random\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flare effect\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"random pixel\"\n        },\n        {\n          \"dmxRange\": [170, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"$pixelKey FX Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\",\n          \"comment\": \"FX Off\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey Flash Rate\"\n          }\n        },\n        {\n          \"dmxRange\": [3, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sync strobe - circle mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [6, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sync strobe - 4 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [9, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sync strobe - 1 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random strobe - all\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random strobe - circle mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [18, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random strobe - 4 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random strobe - 1 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 26],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in/out - all\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [27, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in/out - circle mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in/out - 4 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [33, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in/out - 1 dot mask\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Snake\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [39, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Raindrops\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random pixel\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random fake x 2\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random fake x 4\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Line\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"Double line\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [57, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Corner to corner line\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilted double lines\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [63, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tilted double lines in to out\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"Center line running dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [69, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Middle line running dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer line running dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Corner to corner\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [78, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Arrow\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [84, 86],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wheel\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [87, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Half wheel\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circling dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer circle\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 98],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inner circle\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [99, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer 4 dots\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Outer single dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [105, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Middle single dot\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [108, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Spinning 2x1 dots\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 113],\n          \"type\": \"Effect\",\n          \"effectName\": \"Asymmetrical 4 dots\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [114, 116],\n          \"type\": \"Effect\",\n          \"effectName\": \"Symmetrical 4 dots\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [117, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Square\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inside out\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [123, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inside out 2\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Effect\",\n          \"effectName\": \"Abstract 1\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [129, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Abstract 2\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [132, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Abstract 3\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [135, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hash tag\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [138, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flip flop\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Jumping slash\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Jumping 'L'\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [147, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Jumping pins\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Off - No Strobe or FX\",\n          \"switchChannels\": {\n            \"$pixelKey Flash Rate / FX Speed\": \"$pixelKey FX Speed\"\n          }\n        }\n      ]\n    },\n    \"$pixelKey FX Crossfade Time\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [2, 127],\n          \"type\": \"EffectDuration\",\n          \"durationStart\": \"short\",\n          \"durationEnd\": \"long\",\n          \"comment\": \"Crossfade\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"EffectDuration\",\n          \"durationStart\": \"long\",\n          \"durationEnd\": \"short\",\n          \"comment\": \"Crossfade and tail\"\n        }\n      ]\n    },\n    \"$pixelKey Orientation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 90°\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 180°\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 270°\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Horizontal flip\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 90° & vertical flip\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 180° & horizontal flip\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 270° & vertical flip\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random rotate & flip\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random position\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 90° rotation & random position\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 180° rotation & random position\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 270° rotation & random position\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 90°\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 180°\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 270°\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate CCW at end\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate CW at end\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random rotate at end\"\n        },\n        {\n          \"dmxRange\": [115, 134],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 90° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 180° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 270° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Horizontal flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 90° & vertical flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 180° & horizontal flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate 270° & vertical flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random Rotate & flip (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random position (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 90° rotation & random position (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 180° rotation & random position (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fix 270° rotation & random position (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [210, 214],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 90° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 180° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Bounce & rotate 270° (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate CCW at end (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Rotate CW at end (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random rotate at end (reversed direction)\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        }\n      ]\n    },\n    \"$pixelKey FX Offset\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"$pixelKey FX Length\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"$pixelKey FX Color Generator\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random all pixels RGBCMY\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random single pixel RGBCMY\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random all pixels bright colors\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random single pixel bright colors\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red / Blue\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red / Green\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#00ff00\"],\n          \"comment\": \"Blue / Green\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\", \"#ff00ff\"],\n          \"comment\": \"Yellow / Magenta\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\", \"#00ffff\"],\n          \"comment\": \"Yellow / Cyan\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\", \"#ff00ff\"],\n          \"comment\": \"Cyan / Magenta\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\", \"#0000ff\"],\n          \"comment\": \"Yellow / Blue\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ff00ff\"],\n          \"comment\": \"Green / Magenta\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red / Green / Blue\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffff00\", \"#0000ff\"],\n          \"comment\": \"Red / Yellow / Blue\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffff00\", \"#ff00ff\", \"#00ffff\"],\n          \"comment\": \"Red / Green / Blue / Yellow / Magenta / Cyan\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red / Green / Blue - Horizontal line\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red / Green / Blue - Vertical line\"\n        },\n        {\n          \"dmxRange\": [180, 219],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite in\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lite out\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"$pixelKey Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [5, 39],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [40, 74],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [75, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [110, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Double flash\"\n        },\n        {\n          \"dmxRange\": [145, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Pixel flare effect\"\n        },\n        {\n          \"dmxRange\": [180, 214],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [215, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.289Hz\",\n          \"speedEnd\": \"16.67Hz\"\n        },\n        {\n          \"dmxRange\": [250, 252],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Hyperspeed\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGBW 16-bit\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"White strobe with FX, RGB with FX\",\n      \"shortName\": \"23ch\",\n      \"channels\": [\n        \"White LEDs Dimmer\",\n        \"White LEDs Flash Duration\",\n        \"White LEDs Flash Rate / FX Speed\",\n        \"White LEDs Flare Effect\",\n        \"White LEDs FX Selection\",\n        \"White LEDs FX Crossfade Time\",\n        \"White LEDs Orientation\",\n        \"White LEDs FX Offset\",\n        \"White LEDs FX Length\",\n        \"RGB LEDs Dimmer\",\n        \"RGB LEDs Flash Duration\",\n        \"RGB LEDs Flash Rate / FX Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"RGB LEDs Flare Effect\",\n        \"RGB LEDs FX Selection\",\n        \"RGB LEDs FX Crossfade Time\",\n        \"RGB LEDs Orientation\",\n        \"RGB LEDs FX Offset\",\n        \"RGB LEDs FX Length\",\n        \"RGB LEDs FX Color Generator\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"RGB strobe with FX, White 25-pixel\",\n      \"shortName\": \"40ch\",\n      \"channels\": [\n        \"RGB LEDs Dimmer\",\n        \"RGB LEDs Flash Duration\",\n        \"RGB LEDs Flash Rate / FX Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"RGB LEDs Flare Effect\",\n        \"RGB LEDs FX Selection\",\n        \"RGB LEDs FX Crossfade Time\",\n        \"RGB LEDs Orientation\",\n        \"RGB LEDs FX Offset\",\n        \"RGB LEDs FX Length\",\n        \"RGB LEDs FX Color Generator\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"White Pixel $pixelKey\"\n          ]\n        },\n        \"White LEDs Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"White strobe with FX, RGB 25-pixel\",\n      \"shortName\": \"86ch\",\n      \"channels\": [\n        \"White LEDs Dimmer\",\n        \"White LEDs Flash Duration\",\n        \"White LEDs Flash Rate / FX Speed\",\n        \"White LEDs Flare Effect\",\n        \"White LEDs FX Selection\",\n        \"White LEDs FX Crossfade Time\",\n        \"White LEDs Orientation\",\n        \"White LEDs FX Offset\",\n        \"White LEDs FX Length\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red Pixel $pixelKey\",\n            \"Green Pixel $pixelKey\",\n            \"Blue Pixel $pixelKey\"\n          ]\n        },\n        \"RGB LEDs Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"Multi-layer RGBW with FX\",\n      \"shortName\": \"35ch\",\n      \"channels\": [\n        \"Layer 1 Red\",\n        \"Layer 1 Green\",\n        \"Layer 1 Blue\",\n        \"Layer 1 White\",\n        \"Layer 2 Master\",\n        \"Layer 2 Master fine\",\n        \"Layer 2 Flash Duration\",\n        \"Layer 2 Flash Rate / FX Speed\",\n        \"Layer 2 Flare Effect\",\n        \"Layer 2 Red\",\n        \"Layer 2 Green\",\n        \"Layer 2 Blue\",\n        \"Layer 2 White\",\n        \"Layer 2 FX Selection\",\n        \"Layer 2 FX Crossfade Time\",\n        \"Layer 2 Orientation\",\n        \"Layer 2 FX Offset\",\n        \"Layer 2 FX Length\",\n        \"Layer 2 FX Color Generator\",\n        \"Layer 3 Master\",\n        \"Layer 3 Master fine\",\n        \"Layer 3 Flash Duration\",\n        \"Layer 3 Flash Rate / FX Speed\",\n        \"Layer 3 Flare Effect\",\n        \"Layer 3 Red\",\n        \"Layer 3 Green\",\n        \"Layer 3 Blue\",\n        \"Layer 3 White\",\n        \"Layer 3 FX Selection\",\n        \"Layer 3 FX Crossfade Time\",\n        \"Layer 3 Orientation\",\n        \"Layer 3 FX Offset\",\n        \"Layer 3 FX Length\",\n        \"Layer 3 FX Color Generator\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 25-pixel 8-bit\",\n      \"shortName\": \"102ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red Pixel $pixelKey\",\n            \"Green Pixel $pixelKey\",\n            \"Blue Pixel $pixelKey\",\n            \"White Pixel $pixelKey\"\n          ]\n        },\n        \"Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 25-pixel 16-bit\",\n      \"shortName\": \"202ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red Pixel $pixelKey\",\n            \"Red Pixel $pixelKey fine\",\n            \"Green Pixel $pixelKey\",\n            \"Green Pixel $pixelKey fine\",\n            \"Blue Pixel $pixelKey\",\n            \"Blue Pixel $pixelKey fine\",\n            \"White Pixel $pixelKey\",\n            \"White Pixel $pixelKey fine\"\n          ]\n        },\n        \"Shutter / Strobe\",\n        \"Control / Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/glx/gls-4-led-stage-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"GLS-4 LED Stage 4\",\n  \"shortName\": \"GLX-Stage4\",\n  \"categories\": [\"Stand\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Andrea Beppiani\"],\n    \"createDate\": \"2019-07-11\",\n    \"lastModifyDate\": \"2019-07-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/1044527/Glx-Gls-4-Led-Stage-4.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=842UZEEFHNU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1110, 295, 55],\n    \"weight\": 8,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Spot 1\", \"Spot 2\", \"Spot 3\", \"Spot 4\"]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [190, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [230, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode: Internal Programs\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound controlled Mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"0%\",\n          \"brightnessEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Auto Programs\",\n        \"Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/griven/kolorado-4000.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Kolorado 4000\",\n  \"shortName\": \"GrivenKolorado4000\",\n  \"categories\": [\"Color Changer\", \"Blinder\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"David Olvera\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2019-07-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://www.carlosmendoza.com.mx/Descargas/Griven_Kolorado_4000_manual.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [620, 821, 623],\n    \"weight\": 53,\n    \"power\": 4000,\n    \"bulb\": {\n      \"type\": \"HMI 4000W SE G38\",\n      \"colorTemperature\": 6000,\n      \"lumens\": 380000\n    }\n  },\n  \"availableChannels\": {\n    \"Lamp On/Off\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [127, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Mechanical\"\n        },\n        {\n          \"dmxRange\": [192, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\",\n          \"comment\": \"Electronic\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Lamp On/Off\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Lamp On/Off\",\n        \"Dimmer\",\n        \"Yellow\",\n        \"Cyan\",\n        \"Magenta\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/gruft/pixel-tube.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Pixel Tube\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-09-24\",\n    \"lastModifyDate\": \"2018-11-19\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://codeberg.org/FloEdelmann/dmx-pixel-tubes\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1000, 30, 36.5],\n    \"power\": 10,\n    \"bulb\": {\n      \"type\": \"30x WS2812B RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [270, 270]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [33, 30, 9.5],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [30, 1, 1]\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 29],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"default\"\n        },\n        {\n          \"dmxRange\": [30, 54],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1900K\",\n          \"comment\": \"Candle\"\n        },\n        {\n          \"dmxRange\": [55, 79],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2600K\",\n          \"comment\": \"Tungsten 40W\"\n        },\n        {\n          \"dmxRange\": [80, 104],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2850K\",\n          \"comment\": \"Tungsten 100W\"\n        },\n        {\n          \"dmxRange\": [105, 129],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"Halogen\"\n        },\n        {\n          \"dmxRange\": [130, 154],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5200K\",\n          \"comment\": \"Carbon Arc\"\n        },\n        {\n          \"dmxRange\": [155, 179],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5400K\",\n          \"comment\": \"High Noon Sun\"\n        },\n        {\n          \"dmxRange\": [180, 204],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\",\n          \"comment\": \"Direct Sunlight\"\n        },\n        {\n          \"dmxRange\": [205, 229],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7000K\",\n          \"comment\": \"Overcast Sky\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"20000K\",\n          \"comment\": \"Clear Blue Sky\"\n        }\n      ]\n    },\n    \"Pixel Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB (default orientation)\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"HSV (default orientation)\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB (reverse orientation)\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"HSV (reverse orientation)\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Red 1\",\n            \"Green 1 / Effect Color 1 Green\": \"Green 1\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Blue 1\",\n            \"Red 2 / Effect Color 2 Red\": \"Red 2\",\n            \"Green 2 / Effect Color 2 Green\": \"Green 2\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Blue 2\",\n            \"Red 3 / Effect Color 3 Red\": \"Red 3\",\n            \"Green 3 / Effect Color 3 Green\": \"Green 3\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Blue 3\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blink\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [23, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Breath\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Wipe\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [29, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Wipe Inverse\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Wipe Reverse\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Wipe Reverse Inverse\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Wipe Random\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Color\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [44, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single Dynamic\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [47, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Multi Dynamic\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [53, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow Cycle\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scan\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [59, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dual Scan\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [62, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Theater Chase\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [68, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Theater Chase Rainbow\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running Lights\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [74, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Twinkle\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [77, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Twinkle Random\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Twinkle Fade\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [83, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Twinkle Fade Random\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [86, 88],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sparkle\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [89, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flash Sparkle\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [92, 94],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hyper Sparkle\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [95, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [98, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe Rainbow\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Multi Strobe\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [104, 106],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blink Rainbow\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [107, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase White\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase Color\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [113, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase Random\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [116, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase Rainbow\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [119, 121],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase Flash\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [122, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase Flash Random\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [125, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase Rainbow White\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase Blackout\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase Blackout Rainbow\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [134, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Sweep Random\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [137, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running Color\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running Red Blue\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [143, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running Random\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [146, 148],\n          \"type\": \"Effect\",\n          \"effectName\": \"Larson Scanner\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [149, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Comet\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [155, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks Random\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [158, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Merry Christmas\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire Flicker\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire Flicker (soft)\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire Flicker (intense)\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circus Combustus\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Halloween\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"Effect\",\n          \"effectName\": \"Bicolor Chase\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue\"\n          }\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tricolor Chase\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue\"\n          }\n        },\n        {\n          \"dmxRange\": [182, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"ICU\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [185, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"Red 1 / Effect Color 1 Red\": \"Effect Color 1 Red Unused\",\n            \"Green 1 / Effect Color 1 Green\": \"Effect Color 1 Green Unused\",\n            \"Blue 1 / Effect Color 1 Blue\": \"Effect Color 1 Blue Unused\",\n            \"Red 2 / Effect Color 2 Red\": \"Effect Color 2 Red Unused\",\n            \"Green 2 / Effect Color 2 Green\": \"Effect Color 2 Green Unused\",\n            \"Blue 2 / Effect Color 2 Blue\": \"Effect Color 2 Blue Unused\",\n            \"Red 3 / Effect Color 3 Red\": \"Effect Color 3 Red Unused\",\n            \"Green 3 / Effect Color 3 Green\": \"Effect Color 3 Green Unused\",\n            \"Blue 3 / Effect Color 3 Blue\": \"Effect Color 3 Blue Unused\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 245],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Effect Color 1 Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Effect Color 1 Red Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Effect Color 1 Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Effect Color 1 Green Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Effect Color 1 Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Effect Color 1 Blue Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Effect Color 2 Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Effect Color 2 Red Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Effect Color 2 Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Effect Color 2 Green Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Effect Color 2 Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Effect Color 2 Blue Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Effect Color 3 Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Effect Color 3 Red Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Effect Color 3 Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Effect Color 3 Green Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Effect Color 3 Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Effect Color 3 Blue Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Intensity $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"bright\",\n        \"brightnessEnd\": \"off\"\n      }\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Pixel\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Pixel Control\",\n        \"Auto Programs\",\n        \"Program Speed\",\n        \"Intensity 1\",\n        \"Red 1 / Effect Color 1 Red\",\n        \"Green 1 / Effect Color 1 Green\",\n        \"Blue 1 / Effect Color 1 Blue\",\n        \"Intensity 2\",\n        \"Red 2 / Effect Color 2 Red\",\n        \"Green 2 / Effect Color 2 Green\",\n        \"Blue 2 / Effect Color 2 Blue\",\n        \"Intensity 3\",\n        \"Red 3 / Effect Color 3 Red\",\n        \"Green 3 / Effect Color 3 Green\",\n        \"Blue 3 / Effect Color 3 Blue\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\",\n            \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\",\n            \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"30\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Intensity $pixelKey\",\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/gruft/ventilator.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Ventilator\",\n  \"shortName\": \"Venti\",\n  \"categories\": [\"Fan\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-02-24\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"comment\": \"(C) Görli + Edelnörd 2016\",\n  \"links\": {\n    \"productPage\": [\n      \"https://codeberg.org/FloEdelmann/DMX-Ventilator\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1000, 1000, 160],\n    \"weight\": 10.0,\n    \"power\": 48,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Motor Speed\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [4, 119],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"highlightValue\": 230,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 29],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [30, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\"Motor Speed\", \"Red\", \"Green\", \"Blue\", \"Strobe\"]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hazebase/base-hazer-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"base*hazer*pro\",\n  \"shortName\": \"basehazerpro\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2019-11-05\",\n    \"lastModifyDate\": \"2019-11-05\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.steinigke.de/download/51700100-Manual-82145-hazebase-basehazerpro-hazer-en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.steinigke.de/en/mpn51700100-hazebase-basehazerpro-hazer.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=m1Z7sziCdL0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [594, 185, 540],\n    \"weight\": 18,\n    \"power\": 1500,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Haze\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Haze\",\n        \"fogOutputStart\": \"off\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Fan\": {\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"speedStart\": \"slow CW\",\n        \"speedEnd\": \"fast CW\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Haze\",\n        \"Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hive/bee-50-c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Bee 50-C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-02-20\",\n    \"lastModifyDate\": \"2021-02-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/file/d/1pJK6BaAhvOGTwMP1VhfO8GH25YicCDwS/view\"\n    ],\n    \"productPage\": [\n      \"https://hivelighting.com/c-series/bee-50-c/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=HHbsbvlReC0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [100, 100, 136],\n    \"weight\": 0.7,\n    \"power\": 40,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 180]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"1650K\",\n        \"colorTemperatureEnd\": \"8025K\"\n      }\n    },\n    \"Hue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Sources\": {\n      \"name\": \"Pre-Mixed Color\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f20dcc\"],\n          \"comment\": \"Violet Glow Stick\"\n        },\n        {\n          \"dmxRange\": [16, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f9066b\"],\n          \"comment\": \"Pink Glow Stick\"\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#daec13\"],\n          \"comment\": \"Yellow Glow Stick\"\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red Glow Stick\"\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00fff7\"],\n          \"comment\": \"Green Glow Stick\"\n        },\n        {\n          \"dmxRange\": [42, 46],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0055ff\"],\n          \"comment\": \"Blue Glow Stick\"\n        },\n        {\n          \"dmxRange\": [47, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2330d\"],\n          \"comment\": \"Red Traffic Light\"\n        },\n        {\n          \"dmxRange\": [53, 58],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b9f20d\"],\n          \"comment\": \"Yellow Traffic Light\"\n        },\n        {\n          \"dmxRange\": [59, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#03fcf4\"],\n          \"comment\": \"Green Traffic Light\"\n        },\n        {\n          \"dmxRange\": [65, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2cc0d\"],\n          \"comment\": \"Amber Caution\"\n        },\n        {\n          \"dmxRange\": [71, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ec1313\"],\n          \"comment\": \"Road Flare\"\n        },\n        {\n          \"dmxRange\": [77, 82],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0da6f2\"],\n          \"comment\": \"Blowtorch\"\n        },\n        {\n          \"dmxRange\": [83, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#04f3fb\"],\n          \"comment\": \"Luminescence\"\n        },\n        {\n          \"dmxRange\": [89, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#99666f\"],\n          \"comment\": \"Computer Monitor\"\n        },\n        {\n          \"dmxRange\": [95, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7b738c\"],\n          \"comment\": \"Mobile Phone\"\n        },\n        {\n          \"dmxRange\": [101, 106],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#667f99\"],\n          \"comment\": \"Sun Blue Hour\"\n        },\n        {\n          \"dmxRange\": [107, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8c8073\"],\n          \"comment\": \"Sun Overcast\"\n        },\n        {\n          \"dmxRange\": [113, 123],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#808080\"],\n          \"comment\": \"Sun Direct\"\n        },\n        {\n          \"dmxRange\": [124, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8c737b\"],\n          \"comment\": \"Gas Light\"\n        },\n        {\n          \"dmxRange\": [131, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aabf40\"],\n          \"comment\": \"Candlelight\"\n        },\n        {\n          \"dmxRange\": [137, 142],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#919966\"],\n          \"comment\": \"Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [143, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#889966\"],\n          \"comment\": \"Warm Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [149, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#848c73\"],\n          \"comment\": \"Christmas Lights\"\n        },\n        {\n          \"dmxRange\": [155, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#69705c\"],\n          \"comment\": \"Night Light\"\n        },\n        {\n          \"dmxRange\": [161, 166],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cc2200\"],\n          \"comment\": \"Heat Lamp\"\n        },\n        {\n          \"dmxRange\": [167, 177],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#26d9bb\"],\n          \"comment\": \"Grow Light\"\n        },\n        {\n          \"dmxRange\": [178, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#86797b\"],\n          \"comment\": \"Tungsten Bulb\"\n        },\n        {\n          \"dmxRange\": [185, 190],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#808080\"],\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [191, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#867d79\"],\n          \"comment\": \"Halogen\"\n        },\n        {\n          \"dmxRange\": [197, 202],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#666f99\"],\n          \"comment\": \"HMI\"\n        },\n        {\n          \"dmxRange\": [203, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbf20d\"],\n          \"comment\": \"High Pressure Sodium Vapor\"\n        },\n        {\n          \"dmxRange\": [209, 214],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e5e619\"],\n          \"comment\": \"Low Pressure Sodium Vapor\"\n        },\n        {\n          \"dmxRange\": [215, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#59a6a6\"],\n          \"comment\": \"Mercury Vapor\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#59a699\"],\n          \"comment\": \"Metal Halide\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#996666\"],\n          \"comment\": \"Ceramic\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84738c\"],\n          \"comment\": \"Carbon Arc\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84738c\"],\n          \"comment\": \"Xenon\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5500ff\"],\n          \"comment\": \"Blacklight\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#609f67\"],\n          \"comment\": \"Cool White Fluorescent\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#609f67\"],\n          \"comment\": \"Warm White Fluorescent\"\n        }\n      ]\n    },\n    \"Corrective\": {\n      \"name\": \"Gel Color\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Generic\",\n          \"comment\": \"Full +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Generic\",\n          \"comment\": \"Full -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Full -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Generic\",\n          \"comment\": \"Full CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"Generic\",\n          \"comment\": \"Full CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [231, 240],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 CTS Tungsten\"\n        }\n      ]\n    },\n    \"EFX\": {\n      \"name\": \"Effect\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police Car 1\"\n        },\n        {\n          \"dmxRange\": [29, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police Car 2\"\n        },\n        {\n          \"dmxRange\": [47, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 1\"\n        },\n        {\n          \"dmxRange\": [65, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 2\"\n        },\n        {\n          \"dmxRange\": [83, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 3\"\n        },\n        {\n          \"dmxRange\": [101, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Club Lights\"\n        },\n        {\n          \"dmxRange\": [119, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [137, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Chase\"\n        },\n        {\n          \"dmxRange\": [155, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [173, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [191, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [209, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [227, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        }\n      ]\n    },\n    \"EFX Speed\": {\n      \"name\": \"Effect Speed\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"HSI\",\n      \"shortName\": \"HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\"\n      ]\n    },\n    {\n      \"name\": \"RGB+CCT\",\n      \"shortName\": \"RGB+CCT\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"FX+\",\n      \"shortName\": \"FX+\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\",\n        \"Sources\",\n        \"Corrective\",\n        \"EFX\",\n        \"EFX Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hive/bumble-bee-25-cx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Bumble Bee 25-CX\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-02-20\",\n    \"lastModifyDate\": \"2021-02-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/file/d/1pJK6BaAhvOGTwMP1VhfO8GH25YicCDwS/view\"\n    ],\n    \"productPage\": [\n      \"https://hivelighting.com/bb-25-cx/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Q2pU13V46aw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [100, 100, 67],\n    \"weight\": 0.5,\n    \"power\": 25,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 180]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"1650K\",\n        \"colorTemperatureEnd\": \"8025K\"\n      }\n    },\n    \"Hue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"HSI\",\n      \"shortName\": \"HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hive/hornet-200-c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hornet 200-C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-02-20\",\n    \"lastModifyDate\": \"2021-02-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/file/d/1pJK6BaAhvOGTwMP1VhfO8GH25YicCDwS/view\"\n    ],\n    \"productPage\": [\n      \"https://hivelighting.com/c-series/hornet-200-c/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=B9-TKGy25mQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [100, 100, 224],\n    \"weight\": 2.6,\n    \"power\": 150,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [19, 180]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"1650K\",\n        \"colorTemperatureEnd\": \"8025K\"\n      }\n    },\n    \"Hue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Sources\": {\n      \"name\": \"Pre-Mixed Color\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f20dcc\"],\n          \"comment\": \"Violet Glow Stick\"\n        },\n        {\n          \"dmxRange\": [16, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f9066b\"],\n          \"comment\": \"Pink Glow Stick\"\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#daec13\"],\n          \"comment\": \"Yellow Glow Stick\"\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red Glow Stick\"\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00fff7\"],\n          \"comment\": \"Green Glow Stick\"\n        },\n        {\n          \"dmxRange\": [42, 46],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0055ff\"],\n          \"comment\": \"Blue Glow Stick\"\n        },\n        {\n          \"dmxRange\": [47, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2330d\"],\n          \"comment\": \"Red Traffic Light\"\n        },\n        {\n          \"dmxRange\": [53, 58],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b9f20d\"],\n          \"comment\": \"Yellow Traffic Light\"\n        },\n        {\n          \"dmxRange\": [59, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#03fcf4\"],\n          \"comment\": \"Green Traffic Light\"\n        },\n        {\n          \"dmxRange\": [65, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2cc0d\"],\n          \"comment\": \"Amber Caution\"\n        },\n        {\n          \"dmxRange\": [71, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ec1313\"],\n          \"comment\": \"Road Flare\"\n        },\n        {\n          \"dmxRange\": [77, 82],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0da6f2\"],\n          \"comment\": \"Blowtorch\"\n        },\n        {\n          \"dmxRange\": [83, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#04f3fb\"],\n          \"comment\": \"Luminescence\"\n        },\n        {\n          \"dmxRange\": [89, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#99666f\"],\n          \"comment\": \"Computer Monitor\"\n        },\n        {\n          \"dmxRange\": [95, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7b738c\"],\n          \"comment\": \"Mobile Phone\"\n        },\n        {\n          \"dmxRange\": [101, 106],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#667f99\"],\n          \"comment\": \"Sun Blue Hour\"\n        },\n        {\n          \"dmxRange\": [107, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8c8073\"],\n          \"comment\": \"Sun Overcast\"\n        },\n        {\n          \"dmxRange\": [113, 123],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#808080\"],\n          \"comment\": \"Sun Direct\"\n        },\n        {\n          \"dmxRange\": [124, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8c737b\"],\n          \"comment\": \"Gas Light\"\n        },\n        {\n          \"dmxRange\": [131, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aabf40\"],\n          \"comment\": \"Candlelight\"\n        },\n        {\n          \"dmxRange\": [137, 142],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#919966\"],\n          \"comment\": \"Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [143, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#889966\"],\n          \"comment\": \"Warm Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [149, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#848c73\"],\n          \"comment\": \"Christmas Lights\"\n        },\n        {\n          \"dmxRange\": [155, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#69705c\"],\n          \"comment\": \"Night Light\"\n        },\n        {\n          \"dmxRange\": [161, 166],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cc2200\"],\n          \"comment\": \"Heat Lamp\"\n        },\n        {\n          \"dmxRange\": [167, 177],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#26d9bb\"],\n          \"comment\": \"Grow Light\"\n        },\n        {\n          \"dmxRange\": [178, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#86797b\"],\n          \"comment\": \"Tungsten Bulb\"\n        },\n        {\n          \"dmxRange\": [185, 190],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#808080\"],\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [191, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#867d79\"],\n          \"comment\": \"Halogen\"\n        },\n        {\n          \"dmxRange\": [197, 202],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#666f99\"],\n          \"comment\": \"HMI\"\n        },\n        {\n          \"dmxRange\": [203, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbf20d\"],\n          \"comment\": \"High Pressure Sodium Vapor\"\n        },\n        {\n          \"dmxRange\": [209, 214],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e5e619\"],\n          \"comment\": \"Low Pressure Sodium Vapor\"\n        },\n        {\n          \"dmxRange\": [215, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#59a6a6\"],\n          \"comment\": \"Mercury Vapor\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#59a699\"],\n          \"comment\": \"Metal Halide\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#996666\"],\n          \"comment\": \"Ceramic\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84738c\"],\n          \"comment\": \"Carbon Arc\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84738c\"],\n          \"comment\": \"Xenon\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5500ff\"],\n          \"comment\": \"Blacklight\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#609f67\"],\n          \"comment\": \"Cool White Fluorescent\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#609f67\"],\n          \"comment\": \"Warm White Fluorescent\"\n        }\n      ]\n    },\n    \"Corrective\": {\n      \"name\": \"Gel Color\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Generic\",\n          \"comment\": \"Full +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Generic\",\n          \"comment\": \"Full -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Full -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Generic\",\n          \"comment\": \"Full CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"Generic\",\n          \"comment\": \"Full CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [231, 240],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 CTS Tungsten\"\n        }\n      ]\n    },\n    \"EFX\": {\n      \"name\": \"Effect\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police Car 1\"\n        },\n        {\n          \"dmxRange\": [29, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police Car 2\"\n        },\n        {\n          \"dmxRange\": [47, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 1\"\n        },\n        {\n          \"dmxRange\": [65, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 2\"\n        },\n        {\n          \"dmxRange\": [83, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 3\"\n        },\n        {\n          \"dmxRange\": [101, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Club Lights\"\n        },\n        {\n          \"dmxRange\": [119, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [137, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Chase\"\n        },\n        {\n          \"dmxRange\": [155, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [173, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [191, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [209, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [227, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        }\n      ]\n    },\n    \"EFX Speed\": {\n      \"name\": \"Effect Speed\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"HSI\",\n      \"shortName\": \"HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\"\n      ]\n    },\n    {\n      \"name\": \"RGB+CCT\",\n      \"shortName\": \"RGB+CCT\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"FX+\",\n      \"shortName\": \"FX+\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\",\n        \"Sources\",\n        \"Corrective\",\n        \"EFX\",\n        \"EFX Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hive/hornet-200-cx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hornet 200-CX\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-02-20\",\n    \"lastModifyDate\": \"2021-02-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/file/d/1pJK6BaAhvOGTwMP1VhfO8GH25YicCDwS/view\"\n    ],\n    \"productPage\": [\n      \"https://hivelighting.com/hornet-200-cx/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=n0JaoCZWXVc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [100, 100, 222],\n    \"weight\": 2.2,\n    \"power\": 150,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [19, 180]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"1650K\",\n        \"colorTemperatureEnd\": \"8025K\"\n      }\n    },\n    \"Hue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"HSI\",\n      \"shortName\": \"HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hive/super-hornet-575-c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Super Hornet 575-C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-02-20\",\n    \"lastModifyDate\": \"2021-02-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/file/d/1pJK6BaAhvOGTwMP1VhfO8GH25YicCDwS/view\"\n    ],\n    \"productPage\": [\n      \"https://hivelighting.com/c-series/575-C/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=gzvpdeNpK3o\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [100, 100, 305],\n    \"weight\": 6.9,\n    \"power\": 600,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [19, 180]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"1650K\",\n        \"colorTemperatureEnd\": \"8025K\"\n      }\n    },\n    \"Hue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Sources\": {\n      \"name\": \"Pre-Mixed Color\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f20dcc\"],\n          \"comment\": \"Violet Glow Stick\"\n        },\n        {\n          \"dmxRange\": [16, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f9066b\"],\n          \"comment\": \"Pink Glow Stick\"\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#daec13\"],\n          \"comment\": \"Yellow Glow Stick\"\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red Glow Stick\"\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00fff7\"],\n          \"comment\": \"Green Glow Stick\"\n        },\n        {\n          \"dmxRange\": [42, 46],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0055ff\"],\n          \"comment\": \"Blue Glow Stick\"\n        },\n        {\n          \"dmxRange\": [47, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2330d\"],\n          \"comment\": \"Red Traffic Light\"\n        },\n        {\n          \"dmxRange\": [53, 58],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b9f20d\"],\n          \"comment\": \"Yellow Traffic Light\"\n        },\n        {\n          \"dmxRange\": [59, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#03fcf4\"],\n          \"comment\": \"Green Traffic Light\"\n        },\n        {\n          \"dmxRange\": [65, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2cc0d\"],\n          \"comment\": \"Amber Caution\"\n        },\n        {\n          \"dmxRange\": [71, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ec1313\"],\n          \"comment\": \"Road Flare\"\n        },\n        {\n          \"dmxRange\": [77, 82],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0da6f2\"],\n          \"comment\": \"Blowtorch\"\n        },\n        {\n          \"dmxRange\": [83, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#04f3fb\"],\n          \"comment\": \"Luminescence\"\n        },\n        {\n          \"dmxRange\": [89, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#99666f\"],\n          \"comment\": \"Computer Monitor\"\n        },\n        {\n          \"dmxRange\": [95, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7b738c\"],\n          \"comment\": \"Mobile Phone\"\n        },\n        {\n          \"dmxRange\": [101, 106],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#667f99\"],\n          \"comment\": \"Sun Blue Hour\"\n        },\n        {\n          \"dmxRange\": [107, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8c8073\"],\n          \"comment\": \"Sun Overcast\"\n        },\n        {\n          \"dmxRange\": [113, 123],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#808080\"],\n          \"comment\": \"Sun Direct\"\n        },\n        {\n          \"dmxRange\": [124, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8c737b\"],\n          \"comment\": \"Gas Light\"\n        },\n        {\n          \"dmxRange\": [131, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aabf40\"],\n          \"comment\": \"Candlelight\"\n        },\n        {\n          \"dmxRange\": [137, 142],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#919966\"],\n          \"comment\": \"Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [143, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#889966\"],\n          \"comment\": \"Warm Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [149, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#848c73\"],\n          \"comment\": \"Christmas Lights\"\n        },\n        {\n          \"dmxRange\": [155, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#69705c\"],\n          \"comment\": \"Night Light\"\n        },\n        {\n          \"dmxRange\": [161, 166],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cc2200\"],\n          \"comment\": \"Heat Lamp\"\n        },\n        {\n          \"dmxRange\": [167, 177],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#26d9bb\"],\n          \"comment\": \"Grow Light\"\n        },\n        {\n          \"dmxRange\": [178, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#86797b\"],\n          \"comment\": \"Tungsten Bulb\"\n        },\n        {\n          \"dmxRange\": [185, 190],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#808080\"],\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [191, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#867d79\"],\n          \"comment\": \"Halogen\"\n        },\n        {\n          \"dmxRange\": [197, 202],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#666f99\"],\n          \"comment\": \"HMI\"\n        },\n        {\n          \"dmxRange\": [203, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbf20d\"],\n          \"comment\": \"High Pressure Sodium Vapor\"\n        },\n        {\n          \"dmxRange\": [209, 214],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e5e619\"],\n          \"comment\": \"Low Pressure Sodium Vapor\"\n        },\n        {\n          \"dmxRange\": [215, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#59a6a6\"],\n          \"comment\": \"Mercury Vapor\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#59a699\"],\n          \"comment\": \"Metal Halide\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#996666\"],\n          \"comment\": \"Ceramic\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84738c\"],\n          \"comment\": \"Carbon Arc\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84738c\"],\n          \"comment\": \"Xenon\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5500ff\"],\n          \"comment\": \"Blacklight\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#609f67\"],\n          \"comment\": \"Cool White Fluorescent\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#609f67\"],\n          \"comment\": \"Warm White Fluorescent\"\n        }\n      ]\n    },\n    \"Corrective\": {\n      \"name\": \"Gel Color\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Generic\",\n          \"comment\": \"Full +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Generic\",\n          \"comment\": \"Full -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Full -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Generic\",\n          \"comment\": \"Full CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"Generic\",\n          \"comment\": \"Full CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [231, 240],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 CTS Tungsten\"\n        }\n      ]\n    },\n    \"EFX\": {\n      \"name\": \"Effect\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police Car 1\"\n        },\n        {\n          \"dmxRange\": [29, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police Car 2\"\n        },\n        {\n          \"dmxRange\": [47, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 1\"\n        },\n        {\n          \"dmxRange\": [65, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 2\"\n        },\n        {\n          \"dmxRange\": [83, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 3\"\n        },\n        {\n          \"dmxRange\": [101, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Club Lights\"\n        },\n        {\n          \"dmxRange\": [119, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [137, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Chase\"\n        },\n        {\n          \"dmxRange\": [155, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [173, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [191, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [209, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [227, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        }\n      ]\n    },\n    \"EFX Speed\": {\n      \"name\": \"Effect Speed\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"HSI\",\n      \"shortName\": \"HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\"\n      ]\n    },\n    {\n      \"name\": \"RGB+CCT\",\n      \"shortName\": \"RGB+CCT\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"FX+\",\n      \"shortName\": \"FX+\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\",\n        \"Sources\",\n        \"Corrective\",\n        \"EFX\",\n        \"EFX Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hive/wasp-100-c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Wasp 100-C\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-02-20\",\n    \"lastModifyDate\": \"2021-02-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/file/d/1pJK6BaAhvOGTwMP1VhfO8GH25YicCDwS/view\"\n    ],\n    \"productPage\": [\n      \"https://hivelighting.com/c-series/wasp-100-c/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=IkXY_vIUm8U\",\n      \"https://www.youtube.com/watch?v=5JuWHXsTSXI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [100, 100, 199],\n    \"weight\": 1.1,\n    \"power\": 75,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 180]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"1650K\",\n        \"colorTemperatureEnd\": \"8025K\"\n      }\n    },\n    \"Hue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Sources\": {\n      \"name\": \"Pre-Mixed Color\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f20dcc\"],\n          \"comment\": \"Violet Glow Stick\"\n        },\n        {\n          \"dmxRange\": [16, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f9066b\"],\n          \"comment\": \"Pink Glow Stick\"\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#daec13\"],\n          \"comment\": \"Yellow Glow Stick\"\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red Glow Stick\"\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00fff7\"],\n          \"comment\": \"Green Glow Stick\"\n        },\n        {\n          \"dmxRange\": [42, 46],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0055ff\"],\n          \"comment\": \"Blue Glow Stick\"\n        },\n        {\n          \"dmxRange\": [47, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2330d\"],\n          \"comment\": \"Red Traffic Light\"\n        },\n        {\n          \"dmxRange\": [53, 58],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b9f20d\"],\n          \"comment\": \"Yellow Traffic Light\"\n        },\n        {\n          \"dmxRange\": [59, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#03fcf4\"],\n          \"comment\": \"Green Traffic Light\"\n        },\n        {\n          \"dmxRange\": [65, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f2cc0d\"],\n          \"comment\": \"Amber Caution\"\n        },\n        {\n          \"dmxRange\": [71, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ec1313\"],\n          \"comment\": \"Road Flare\"\n        },\n        {\n          \"dmxRange\": [77, 82],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0da6f2\"],\n          \"comment\": \"Blowtorch\"\n        },\n        {\n          \"dmxRange\": [83, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#04f3fb\"],\n          \"comment\": \"Luminescence\"\n        },\n        {\n          \"dmxRange\": [89, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#99666f\"],\n          \"comment\": \"Computer Monitor\"\n        },\n        {\n          \"dmxRange\": [95, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7b738c\"],\n          \"comment\": \"Mobile Phone\"\n        },\n        {\n          \"dmxRange\": [101, 106],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#667f99\"],\n          \"comment\": \"Sun Blue Hour\"\n        },\n        {\n          \"dmxRange\": [107, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8c8073\"],\n          \"comment\": \"Sun Overcast\"\n        },\n        {\n          \"dmxRange\": [113, 123],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#808080\"],\n          \"comment\": \"Sun Direct\"\n        },\n        {\n          \"dmxRange\": [124, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8c737b\"],\n          \"comment\": \"Gas Light\"\n        },\n        {\n          \"dmxRange\": [131, 136],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aabf40\"],\n          \"comment\": \"Candlelight\"\n        },\n        {\n          \"dmxRange\": [137, 142],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#919966\"],\n          \"comment\": \"Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [143, 148],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#889966\"],\n          \"comment\": \"Warm Antique Bulb\"\n        },\n        {\n          \"dmxRange\": [149, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#848c73\"],\n          \"comment\": \"Christmas Lights\"\n        },\n        {\n          \"dmxRange\": [155, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#69705c\"],\n          \"comment\": \"Night Light\"\n        },\n        {\n          \"dmxRange\": [161, 166],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cc2200\"],\n          \"comment\": \"Heat Lamp\"\n        },\n        {\n          \"dmxRange\": [167, 177],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#26d9bb\"],\n          \"comment\": \"Grow Light\"\n        },\n        {\n          \"dmxRange\": [178, 184],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#86797b\"],\n          \"comment\": \"Tungsten Bulb\"\n        },\n        {\n          \"dmxRange\": [185, 190],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#808080\"],\n          \"comment\": \"Incandescent\"\n        },\n        {\n          \"dmxRange\": [191, 196],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#867d79\"],\n          \"comment\": \"Halogen\"\n        },\n        {\n          \"dmxRange\": [197, 202],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#666f99\"],\n          \"comment\": \"HMI\"\n        },\n        {\n          \"dmxRange\": [203, 208],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbf20d\"],\n          \"comment\": \"High Pressure Sodium Vapor\"\n        },\n        {\n          \"dmxRange\": [209, 214],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e5e619\"],\n          \"comment\": \"Low Pressure Sodium Vapor\"\n        },\n        {\n          \"dmxRange\": [215, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#59a6a6\"],\n          \"comment\": \"Mercury Vapor\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#59a699\"],\n          \"comment\": \"Metal Halide\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#996666\"],\n          \"comment\": \"Ceramic\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84738c\"],\n          \"comment\": \"Carbon Arc\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#84738c\"],\n          \"comment\": \"Xenon\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5500ff\"],\n          \"comment\": \"Blacklight\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#609f67\"],\n          \"comment\": \"Cool White Fluorescent\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#609f67\"],\n          \"comment\": \"Warm White Fluorescent\"\n        }\n      ]\n    },\n    \"Corrective\": {\n      \"name\": \"Gel Color\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 +Green Daylight\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Generic\",\n          \"comment\": \"Full +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 +Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Generic\",\n          \"comment\": \"Full -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 -Green Daylight\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Full -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 -Green Tungsten\"\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Generic\",\n          \"comment\": \"Full CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 CTS Daylight\"\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"Generic\",\n          \"comment\": \"Full CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"Generic\",\n          \"comment\": \"1/2 CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [231, 240],\n          \"type\": \"Generic\",\n          \"comment\": \"1/4 CTS Tungsten\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"1/8 CTS Tungsten\"\n        }\n      ]\n    },\n    \"EFX\": {\n      \"name\": \"Effect\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police Car 1\"\n        },\n        {\n          \"dmxRange\": [29, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police Car 2\"\n        },\n        {\n          \"dmxRange\": [47, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 1\"\n        },\n        {\n          \"dmxRange\": [65, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 2\"\n        },\n        {\n          \"dmxRange\": [83, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Emergency 3\"\n        },\n        {\n          \"dmxRange\": [101, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Club Lights\"\n        },\n        {\n          \"dmxRange\": [119, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [137, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Chase\"\n        },\n        {\n          \"dmxRange\": [155, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [173, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fireworks\"\n        },\n        {\n          \"dmxRange\": [191, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsing\"\n        },\n        {\n          \"dmxRange\": [209, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [227, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        }\n      ]\n    },\n    \"EFX Speed\": {\n      \"name\": \"Effect Speed\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"HSI\",\n      \"shortName\": \"HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\"\n      ]\n    },\n    {\n      \"name\": \"RGB+CCT\",\n      \"shortName\": \"RGB+CCT\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"FX+\",\n      \"shortName\": \"FX+\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\",\n        \"Sources\",\n        \"Corrective\",\n        \"EFX\",\n        \"EFX Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hive/wasp-100-cx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Wasp 100-CX\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-02-20\",\n    \"lastModifyDate\": \"2021-02-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/file/d/1pJK6BaAhvOGTwMP1VhfO8GH25YicCDwS/view\"\n    ],\n    \"productPage\": [\n      \"https://hivelighting.com/wasp-100-cx/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=5JuWHXsTSXI&t=22s\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [100, 100, 199],\n    \"weight\": 0.9,\n    \"power\": 75,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 180]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"1650K\",\n        \"colorTemperatureEnd\": \"8025K\"\n      }\n    },\n    \"Hue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"HSI\",\n      \"shortName\": \"HSI\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\",\n        \"Saturation\",\n        \"Hue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hong-yi/hy-g60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"HY-G60\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"DJMaxone.de\"],\n    \"createDate\": \"2018-12-12\",\n    \"lastModifyDate\": \"2018-12-12\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-12-12\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.2)\"\n    }\n  },\n  \"links\": {\n    \"video\": [\n      \"https://www.youtube.com/watch?v=M98TE_nUW9U\"\n    ],\n    \"manual\": [\n      \"https://github.com/user-attachments/files/23186632/HY-G60.Manual.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [170, 190, 150],\n    \"weight\": 4.5,\n    \"power\": 100,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"60W white LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#19ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ff01fb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00fbff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [22, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [33, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [44, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [55, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [66, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [77, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [88, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [99, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [110, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [121, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [132, 142],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [143, 153],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [154, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [160, 207],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [208, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [150, 202],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [203, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Internal Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fast Moving\"\n        },\n        {\n          \"dmxRange\": [152, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Internal Programs\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/hsl/40w-beam-spot-light-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"40W Beam Spot Light RGBW\",\n  \"categories\": [\"Color Changer\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"David Oleniacz\", \"Ryan Goodwin\"],\n    \"createDate\": \"2023-06-24\",\n    \"lastModifyDate\": \"2023-06-24\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.amazon.com/Stage-Spotlight-Beam-Light-Package/dp/B07XYYK28H\"\n    ],\n    \"other\": [\n      \"https://www.amazon.com/ask/questions/Tx3CE66RTIHOGZL/ref=ask_dp_dpmw_al_hza\"\n    ]\n  },\n  \"physical\": {\n    \"DMXconnector\": \"3-pin\",\n    \"dimensions\": [127, 127, 190],\n    \"power\": 40,\n    \"weight\": 1.36\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"SMD Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\",\n        \"helpWanted\": \"Are the SMD LEDs the ring around the main light source?\"\n      }\n    },\n    \"SMD Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"SMD Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Program Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program\",\n          \"helpWanted\": \"What are the internal programs? How many are there? What are their DMX values?\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"SMD Red\",\n        \"SMD Green\",\n        \"SMD Blue\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Program Mode\",\n        \"Program Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"SMD Red\",\n        \"SMD Green\",\n        \"SMD Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ibiza-light/lp64-led-promo.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LP64 LED-PROMO\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Proteus\"],\n    \"createDate\": \"2019-12-13\",\n    \"lastModifyDate\": \"2019-12-13\"\n  },\n  \"comment\": \"LED PAR64 CAN\",\n  \"links\": {\n    \"manual\": [\n      \"https://lotronic.net/gb/index.php?controller=attachment&id_attachment=202\"\n    ],\n    \"productPage\": [\n      \"https://lotronic.net/gb/projector/411-LP64LED-PROMO-5420047121066.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [220, 220, 325],\n    \"weight\": 2.8,\n    \"power\": 36,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"177× 5mm RGB LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX Auto\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX Sound\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Programs\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ibiza-light/ls-005led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LS-005LED\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Tormant\"],\n    \"createDate\": \"2019-07-29\",\n    \"lastModifyDate\": \"2019-07-29\"\n  },\n  \"links\": {\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Ojwpf-J7rvQ\"\n    ]\n  },\n  \"helpWanted\": \"Can you provide a link to a manual, product page, or similar?\",\n  \"physical\": {\n    \"dimensions\": [460, 160, 140],\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Intensity\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ibiza-light/par-mini-rgb3.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR CAN 12x3W 3-in-1 RGB\",\n  \"shortName\": \"Ibiza-PAR-MINI-RGB3\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"RAZAKANIRINA\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-10-06\",\n    \"lastModifyDate\": \"2018-10-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://lotronic.net/gb/index.php?controller=attachment&id_attachment=84\"\n    ],\n    \"productPage\": [\n      \"https://lotronic.net/gb/projector/159-PAR-MINI-RGB3-5420047129680.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [120, 120, 90],\n    \"weight\": 0.6,\n    \"power\": 40,\n    \"bulb\": {\n      \"type\": \"12x 3W RGB LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual control\"\n        },\n        {\n          \"dmxRange\": [11, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macro\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        }\n      ]\n    },\n    \"Color Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"7 Color Recycle\",\n          \"helpWanted\": \"Does this enable the color jump effect as well?\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Purple\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"RG\",\n          \"helpWanted\": \"Is this a color jump effect with only these two colors?\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"RB\",\n          \"helpWanted\": \"Is this a color jump effect with only these two colors?\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"GB\",\n          \"helpWanted\": \"Is this a color jump effect with only these two colors?\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"RGB\",\n          \"helpWanted\": \"Is this a color jump effect with only these three colors?\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Is it slow…fast or fast…slow?\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"PAR-MINI-RGB3\",\n      \"channels\": [\n        \"Mode\",\n        \"Color Macro\",\n        \"Effect Speed\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ignition/2bright-par-18-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"2bright Par 18 IP\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\"],\n    \"createDate\": \"2022-06-17\",\n    \"lastModifyDate\": \"2022-06-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_481058_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/ignition_2bright_par_18_ip.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i8896p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [290, 220, 140],\n    \"weight\": 7.5,\n    \"power\": 200,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18× 12W 6in1 RGBWA UV LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"3200K\",\n          \"colorTemperatureEnd\": \"7200K\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blackout\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [11, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"dmxRange\": [17, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [20, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [23, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\",\n          \"colors\": [\"#53b2ff\"]\n        },\n        {\n          \"dmxRange\": [26, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [29, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [32, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff9def\"]\n        },\n        {\n          \"dmxRange\": [35, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime\",\n          \"colors\": [\"#c8ff00\"]\n        },\n        {\n          \"dmxRange\": [38, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Grey (dimmed white)\",\n          \"colors\": [\"#8a8a8a\"]\n        },\n        {\n          \"dmxRange\": [41, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / orangeish\",\n          \"colors\": [\"#ff1e00\"]\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / more orangeish\",\n          \"colors\": [\"#ff3c00\"]\n        },\n        {\n          \"dmxRange\": [46, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / even more orangeish\",\n          \"colors\": [\"#ff5100\"]\n        },\n        {\n          \"dmxRange\": [50, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / even even more orangeish\",\n          \"colors\": [\"#ff6600\"]\n        },\n        {\n          \"dmxRange\": [53, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff9100\"]\n        },\n        {\n          \"dmxRange\": [59, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dimmed orange\",\n          \"colors\": [\"#9b5800\"]\n        },\n        {\n          \"dmxRange\": [62, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dimmed yellow\",\n          \"colors\": [\"#9b9100\"]\n        },\n        {\n          \"dmxRange\": [65, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Greenish yellow\",\n          \"colors\": [\"#eeff00\"]\n        },\n        {\n          \"dmxRange\": [68, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"More greenish yellow\",\n          \"colors\": [\"#c8ff00\"]\n        },\n        {\n          \"dmxRange\": [71, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green / slightly turquoise\",\n          \"colors\": [\"#00ff40\"]\n        },\n        {\n          \"dmxRange\": [74, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green / more turquoise\",\n          \"colors\": [\"#00ff80\"]\n        },\n        {\n          \"dmxRange\": [77, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#00ff9e\"]\n        },\n        {\n          \"dmxRange\": [80, 82],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\",\n          \"colors\": [\"#00e1ff\"]\n        },\n        {\n          \"dmxRange\": [83, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky blue\",\n          \"colors\": [\"#00bfff\"]\n        },\n        {\n          \"dmxRange\": [86, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark blue\",\n          \"colors\": [\"#0026ff\"]\n        },\n        {\n          \"dmxRange\": [89, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale pink\",\n          \"colors\": [\"#ffd2f7\"]\n        },\n        {\n          \"dmxRange\": [92, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"More pink\",\n          \"colors\": [\"#ffa6f0\"]\n        },\n        {\n          \"dmxRange\": [95, 97],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright pink\",\n          \"colors\": [\"#ff60ec\"]\n        },\n        {\n          \"dmxRange\": [98, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark red\",\n          \"colors\": [\"#910000\"]\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Grey\",\n          \"colors\": [\"#8a8a8a\"]\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter grey\",\n          \"colors\": [\"#b3b3b3\"]\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White / slightly blueish\",\n          \"colors\": [\"#ceffff\"]\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White / more blueish\",\n          \"colors\": [\"#8affff\"]\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"Linear course\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Exponential course\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Generic\",\n          \"comment\": \"Logarithmic course\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"S-courve shaped course\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Macros\",\n        \"Color Temperature\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ignition/led-accu-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Accu PAR\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Karl Humbug\"],\n    \"createDate\": \"2019-05-15\",\n    \"lastModifyDate\": \"2019-05-15\"\n  },\n  \"comment\": \"Supports Wireless DMX (WDMX).\",\n  \"links\": {\n    \"manual\": [\n      \"https://bklumitec.com/out/media/87401_BA_E_Ignition_Accu_Par_RGB_W.pdf\"\n    ],\n    \"productPage\": [\n      \"https://bklumitec.com/en/LIGHT/Light-technics/Spotlights/Battery/LED-Accu-PAR-64-Floor-RGB-W-polish.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [285, 377.5, 274],\n    \"weight\": 7.1,\n    \"power\": 65,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"10× 3W RGB LEDs + 5× 3W Cool White LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"36 color presets\",\n          \"helpWanted\": \"Which color can be selected at which DMX value?\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cold White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"12Hz\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3-color, random\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7-color, random\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound to light\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"name\": \"Dimmer\",\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"helpWanted\": \"What's the difference to the other Dimmer channel? Is this 'Effect Intensity'?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1 / 1-channel\",\n      \"shortName\": \"1-1ch\",\n      \"channels\": [\n        \"Color Presets\"\n      ]\n    },\n    {\n      \"name\": \"2 / 2-channel\",\n      \"shortName\": \"2-2ch\",\n      \"channels\": [\n        \"Color Presets\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3 / 3-channel\",\n      \"shortName\": \"3-3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4 / 4-channel\",\n      \"shortName\": \"4-4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"5 / 6-channel\",\n      \"shortName\": \"5-6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6 / 8-channel 1\",\n      \"shortName\": \"6-8ch1\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Effects\",\n        \"Effect Speed\"\n      ]\n    },\n    {\n      \"name\": \"7 / 8-channel 2\",\n      \"shortName\": \"7-8ch2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Effects\",\n        \"Dimmer 2\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ignition/strip-blinder-x.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Strip Blinder X\",\n  \"categories\": [\"Blinder\", \"Pixel Bar\"],\n  \"meta\": {\n    \"authors\": [\"pitchbent\"],\n    \"createDate\": \"2026-01-28\",\n    \"lastModifyDate\": \"2026-01-28\"\n  },\n  \"comment\": \"10x 75W Halogen\",\n  \"links\": {\n    \"manual\": [\n      \"https://images.thomann.de/pics/atg/atgdata/document/manual/319794_c_319794_de_online.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=jWxoSHw4zek\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [140, 78, 1000],\n    \"weight\": 5.4,\n    \"power\": 750,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"Halogen\"\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [10, 1, 1],\n    \"pixelGroups\": {\n      \"All\": \"all\",\n      \"Left\": [\"1\", \"2\", \"3\", \"4\", \"5\"],\n      \"Right\": [\"6\", \"7\", \"8\", \"9\", \"10\"],\n      \"Group 1\": [\"1\", \"2\"],\n      \"Group 2\": [\"3\", \"4\"],\n      \"Group 3\": [\"5\", \"6\"],\n      \"Group 4\": [\"7\", \"8\"],\n      \"Group 5\": [\"9\", \"10\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Intensity $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Intensity All\"\n      ]\n    },\n    {\n      \"name\": \"2-channel Left Right\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Intensity Left\",\n        \"Intensity Right\"\n      ]\n    },\n    {\n      \"name\": \"5-channel 5-Group\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Intensity Group 1\",\n        \"Intensity Group 2\",\n        \"Intensity Group 3\",\n        \"Intensity Group 4\",\n        \"Intensity Group 5\"\n      ]\n    },\n    {\n      \"name\": \"10-channel Single\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ignition/teatro-led-spot-100-fr.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Teatro LED Spot 100 FR\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Victor Hampel\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-06-09\",\n    \"lastModifyDate\": \"2022-06-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/1370155/Ignition-Teatro-Led-Spot-100-Pc.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [214, 188, 315],\n    \"weight\": 5.2,\n    \"power\": 150,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 3000\n    },\n    \"lens\": {\n      \"name\": \"Ø 112mm Fresnel lens\",\n      \"degreesMinMax\": [17, 82]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [30, 119],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"3.27s\",\n          \"durationEnd\": \"0.03s\"\n        },\n        {\n          \"dmxRange\": [120, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"durationStart\": \"42.6s\",\n          \"durationEnd\": \"0.12s\"\n        },\n        {\n          \"dmxRange\": [150, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"durationStart\": \"42.6s\",\n          \"durationEnd\": \"0.12s\"\n        },\n        {\n          \"dmxRange\": [180, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [230, 235],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash 30 ms\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [25, 26],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 1 (25ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 2 (50ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 3 (75ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [31, 32],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 4 (100ms, default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [33, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 5 (125ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [35, 36],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 6 (150ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [37, 38],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 7 (175ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 8 (200ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [41, 42],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 9 (225ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [43, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 10 (250ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [45, 46],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 11 (275ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [47, 48],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 12 (300ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 13 (325ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [51, 52],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 14 (350ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [53, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 15 (375ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [55, 56],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 16 (400ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 17 (425ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 18 (450ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 19 (475ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 20 (500ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [65, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gamma correction: quadratic (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [75, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gamma correction: linear\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [85, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 610Hz (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 800Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 1000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 1500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 2000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 2500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 3000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 3500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 4000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 4500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 5000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 5500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 6000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 6500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 7000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 7500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 8000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 8500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [122, 122],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 9000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 9500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 10000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 11000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 12000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 13000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 14000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 15000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 16000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 17000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 18000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [133, 133],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 19000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 20000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [135, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Boost: on (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [145, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Boost: off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [155, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display stand-by: off (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [165, 174],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display stand-by: on\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [175, 176],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: keep last DMX (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [177, 178],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: blackout\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [179, 180],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: LED on @ 100% (ZOOM @ 50%)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [181, 182],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: LED on @ 60% (ZOOM @ 50%)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [183, 184],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: custom (default: Dimmer 255; Shutter 015; Zoom 128)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [185, 194],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [195, 204],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [205, 214],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [215, 224],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [225, 234],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode: standard\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode: silent (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom mode: standard\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom mode: silent (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Set all default values\",\n          \"hold\": \"5s\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Zoom\",\n          \"hold\": \"3s\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Functions\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ignition/teatro-led-spot-100-pc.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Teatro LED Spot 100 PC\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Victor Hampel\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-06-09\",\n    \"lastModifyDate\": \"2022-06-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/1370155/Ignition-Teatro-Led-Spot-100-Pc.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [214, 188, 315],\n    \"weight\": 5.5,\n    \"power\": 150,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 3000\n    },\n    \"lens\": {\n      \"name\": \"Ø 120mm PC lens\",\n      \"degreesMinMax\": [12, 79]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [30, 119],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"3.27s\",\n          \"durationEnd\": \"0.03s\"\n        },\n        {\n          \"dmxRange\": [120, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"durationStart\": \"42.6s\",\n          \"durationEnd\": \"0.12s\"\n        },\n        {\n          \"dmxRange\": [150, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"durationStart\": \"42.6s\",\n          \"durationEnd\": \"0.12s\"\n        },\n        {\n          \"dmxRange\": [180, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [230, 235],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash 30 ms\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [25, 26],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 1 (25ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 2 (50ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 3 (75ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [31, 32],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 4 (100ms, default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [33, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 5 (125ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [35, 36],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 6 (150ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [37, 38],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 7 (175ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 8 (200ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [41, 42],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 9 (225ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [43, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 10 (250ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [45, 46],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 11 (275ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [47, 48],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 12 (300ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 13 (325ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [51, 52],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 14 (350ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [53, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 15 (375ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [55, 56],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 16 (400ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 17 (425ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 18 (450ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 19 (475ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth: 20 (500ms)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [65, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gamma correction: quadratic (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [75, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gamma correction: linear\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [85, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 610Hz (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 800Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 1000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 1500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 2000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 2500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 3000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 3500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 4000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 4500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 5000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 5500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 6000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 6500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 7000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 7500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 8000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 8500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [122, 122],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 9000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 9500Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 10000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 11000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 12000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 13000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 14000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 15000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 16000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 17000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 18000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [133, 133],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 19000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Output frequency: 20000Hz\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [135, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Boost: on (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [145, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Boost: off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [155, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display stand-by: off (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [165, 174],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display stand-by: on\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [175, 176],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: keep last DMX (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [177, 178],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: blackout\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [179, 180],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: LED on @ 100% (ZOOM @ 50%)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [181, 182],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: LED on @ 60% (ZOOM @ 50%)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [183, 184],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No DMX action: custom (default: Dimmer 255; Shutter 015; Zoom 128)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [185, 194],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [195, 204],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [205, 214],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [215, 224],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [225, 234],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode: standard\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode: silent (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [245, 248],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom mode: standard\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [249, 252],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom mode: silent (default)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Set all default values\",\n          \"hold\": \"5s\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Zoom\",\n          \"hold\": \"3s\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Functions\",\n        \"Zoom\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ikan/stryder-sfb150.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stryder SFB150\",\n  \"categories\": [\"Other\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2024-05-07\",\n    \"lastModifyDate\": \"2024-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://ikancorp.com/Downloads/SFB150-QuickStartGuide.pdf\"\n    ],\n    \"productPage\": [\n      \"https://ikancorp.com/shop/studio-broadcast/dmx-lights-studio-broadcast/stryder-fanless-bi-color-2800k-6500k-150-watt-led-fresnel-light-w-dmx/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [406, 254, 178],\n    \"weight\": 4.8,\n    \"power\": 98,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2800K\",\n        \"colorTemperatureEnd\": \"6500K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Default\",\n      \"channels\": [\n        \"Intensity\",\n        \"CCT\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/infinity/iw-340-rdm.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"iW-340 RDM\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-11-07\",\n    \"lastModifyDate\": \"2018-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/41525_MANUAL_GB_V1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/41525-iw-340-rdm.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=S7FJLurJ6GM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 350, 190],\n    \"weight\": 7.2,\n    \"power\": 145,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"3x 40W RGBW Osram Ostar LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4.5, 36]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"2\", null, \"3\"],\n        [null, \"1\", null]\n      ]\n    ]\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 50],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"20Hz\",\n          \"speedEnd\": \"0Hz\"\n        },\n        {\n          \"dmxRange\": [51, 54],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [55, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"20Hz\",\n          \"speedEnd\": \"0Hz\"\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [100, 140],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"20Hz\",\n          \"speedEnd\": \"0Hz\"\n        },\n        {\n          \"dmxRange\": [141, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [145, 195],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [200, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"20Hz\",\n          \"speedEnd\": \"0Hz\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"CTC\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"1900K\",\n          \"colorTemperatureEnd\": \"2700K\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 2],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa757\"],\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [3, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd3af\"],\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [7, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dde6ff\"],\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [12, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Cyan\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [50, 86],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Green\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [87, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [88, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Yellow\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [126, 162],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Red\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [163, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [164, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Purple\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [202, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple … Blue\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Static Pixel Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LED Pixel 1\"\n        },\n        {\n          \"dmxRange\": [52, 91],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LED Pixel 2\"\n        },\n        {\n          \"dmxRange\": [92, 131],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LED Pixel 3\"\n        },\n        {\n          \"dmxRange\": [132, 171],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LED Pixel 1 & 2\"\n        },\n        {\n          \"dmxRange\": [172, 211],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LED Pixel 2 & 3\"\n        },\n        {\n          \"dmxRange\": [212, 251],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LED Pixel 1 & 3\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All LED Pixels\"\n        }\n      ]\n    },\n    \"Dynamic LED Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [30, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [45, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [60, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [75, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [135, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9 with color flow\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10 with color flow\"\n        },\n        {\n          \"dmxRange\": [165, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11 with color flow\"\n        },\n        {\n          \"dmxRange\": [180, 194],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12 with color flow\"\n        },\n        {\n          \"dmxRange\": [195, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13 with color flow\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14 with color flow\"\n        },\n        {\n          \"dmxRange\": [225, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15 with color flow\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16 with color flow\"\n        }\n      ]\n    },\n    \"Speed Dynamic LED Control\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Fade Time Dynamic LED Control\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"long\",\n        \"durationEnd\": \"short\"\n      }\n    },\n    \"Background Dimmer\": {\n      \"fineChannelAliases\": [\"Background Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Background Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 2],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa757\"],\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [3, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd3af\"],\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [7, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dde6ff\"],\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [12, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Cyan\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [50, 86],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Green\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [87, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [88, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Yellow\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [126, 162],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Red\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [163, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [164, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Purple\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [202, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple … Blue\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"4.5deg\",\n        \"angleEnd\": \"36deg\"\n      }\n    },\n    \"Channel Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan/Tilt Blackout activated\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan/Tilt Blackout deactivated\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"fast\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan/Tilt Speed\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"slow\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan/Tilt Speed\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer Curve Linear\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer Curve Square\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer Curve Inv-Square\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer Curve S-Curve\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"fast\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"slow\",\n          \"hold\": \"5s\",\n          \"comment\": \"Dimmer\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"CMY color mix\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"RGBW color mix\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM 1200Hz\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM 2000Hz\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM 2400Hz\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM 6000K\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"PWM 25000Hz\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"slow\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fan\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"fast\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fan\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Auto test\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan/Tilt reset\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Zoom reset\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Total reset\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"21-channel\",\n      \"shortName\": \"21ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CTC\",\n        \"Color Macros\",\n        \"Static Pixel Control\",\n        \"Dynamic LED Control\",\n        \"Speed Dynamic LED Control\",\n        \"Fade Time Dynamic LED Control\",\n        \"Background Dimmer\",\n        \"Background Color Macros\",\n        \"Zoom\",\n        \"Channel Functions\"\n      ]\n    },\n    {\n      \"name\": \"28-channel\",\n      \"shortName\": \"28ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTC\",\n        \"Color Macros\",\n        \"Static Pixel Control\",\n        \"Dynamic LED Control\",\n        \"Speed Dynamic LED Control\",\n        \"Fade Time Dynamic LED Control\",\n        \"Background Dimmer\",\n        \"Background Dimmer fine\",\n        \"Background Color Macros\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Channel Functions\"\n      ]\n    },\n    {\n      \"name\": \"27-channel\",\n      \"shortName\": \"27ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Channel Functions\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"15-channel (DMX)\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Channel Functions\"\n      ]\n    },\n    {\n      \"name\": \"12-channel (Art-Net)\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/infinity/iw-720-rdm.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"iW-720 RDM\",\n  \"shortName\": \"infinityIW720\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"zuvieltv\"],\n    \"createDate\": \"2020-02-15\",\n    \"lastModifyDate\": \"2020-02-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/41524_MANUAL_GB_V1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/41524-iw-720-rdm.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=HlHJ84QR5p4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [285, 390, 197],\n    \"weight\": 8,\n    \"power\": 170,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7× 20W Osram RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 50]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [         null, null,    \"Top\", null,           null],\n        [   \"Left-top\", null,     null, null,    \"Right-top\"],\n        [         null, null, \"Center\", null,           null],\n        [\"Left-bottom\", null,     null, null, \"Right-bottom\"],\n        [         null, null, \"Bottom\", null,           null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1\": [\"Top\", \"Right-top\"],\n      \"2\": [\"Right-bottom\", \"Bottom\"],\n      \"3\": [\"Left-bottom\", \"Left-top\"],\n      \"4\": [\"Center\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Mobile Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 1 (no movement)\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 2 (no movement)\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 3 (no movement)\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 4 (no movement)\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 5 (no movement)\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 6 (no movement)\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 7 (no movement)\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 8 (no movement)\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 9 (no movement)\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 10 (no movement)\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 11 (no movement)\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 12 (no movement)\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 13 (no movement)\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 14 (no movement)\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"LED program 15 (no movement)\"\n        }\n      ]\n    },\n    \"Built-in Colors\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 33\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 34\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [180, 201],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [208, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [235, 249],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active color change\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [25, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Shutter open\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Lightning\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [230, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"50deg\",\n        \"angleEnd\": \"7deg\"\n      }\n    },\n    \"Channel Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset Pan after 3 seconds\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset Tilt after 3 seconds\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset Zoom after 3 seconds\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan Full Speed\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan Temperature controlled\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimming Fast\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimming Smooth\"\n        },\n        {\n          \"dmxRange\": [145, 239],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"XY Smoothing model open\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"XY Smoothing model to shut down\"\n        }\n      ]\n    },\n    \"Built-in Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Macro 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Macro 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Macro 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Macro 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Macro 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Macro 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Macro 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Macro 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Macro 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Macro 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Macro 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Macro 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Macro 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Macro 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 246],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Macro 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [247, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Macro 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"29-channel\",\n      \"shortName\": \"29ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1\", \"2\", \"3\", \"4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Built-in Colors\",\n        \"Mobile Macros\",\n        \"Macro Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Zoom\",\n        \"Channel Functions\",\n        \"Built-in Programs\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Mobile Macros\",\n        \"Macro Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Zoom\",\n        \"Channel Functions\",\n        \"Built-in Programs\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Mobile Macros\",\n        \"Macro Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Zoom\",\n        \"Channel Functions\",\n        \"Built-in Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/jb-lighting/jbled-a7.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"JBLED A7\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Swiftb0y\"],\n    \"createDate\": \"2019-11-29\",\n    \"lastModifyDate\": \"2019-11-29\"\n  },\n  \"comment\": \"Wash RGB LED Moving Head\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.jb-lighting.de/download/Handbuch/JBLED_A7_Manual.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=OBVMcR1yKqw\",\n      \"https://www.youtube.com/watch?v=T8IXQbxDiQI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [315, 388, 200],\n    \"weight\": 8.9,\n    \"power\": 350,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleEnd\": \"0deg\",\n        \"angleStart\": \"430deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"300deg\"\n      }\n    },\n    \"Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"default\",\n          \"comment\": \"full output power\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8500K\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Linear color balance for color picker function\"\n        },\n        {\n          \"dmxRange\": [32, 207],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Camera mode 50Hz\",\n          \"hold\": \"2s\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Camera mode 60Hz\",\n          \"hold\": \"2s\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Camera mode flex (use device setting)\",\n          \"hold\": \"2s\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"2s\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [96, 110],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speed\": \"fast\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.8s\"\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [112, 125],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"fade effect with dimmer\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speed\": \"slow\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.8s\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [144, 158],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.6s\"\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [160, 174],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"0%\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.8s\"\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [176, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"100%\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.8s\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [192, 206],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"100%\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.8s\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [208, 222],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"0%\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.8s\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [224, 238],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speed\": \"0%\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.8s\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speed\": \"100%\",\n          \"durationStart\": \"0.6s\",\n          \"durationEnd\": \"4.8s\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": 25,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"12deg\",\n        \"angleEnd\": \"36deg\",\n        \"comment\": \"1/10 peak measurement\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"CTC\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2900K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    },\n    \"Virtual Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [2, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White / Red\",\n          \"colors\": [\"#ffffff\", \"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red / Yellow\",\n          \"colors\": [\"#ff0000\", \"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow / Magenta\",\n          \"colors\": [\"#ffff00\", \"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta / Green\",\n          \"colors\": [\"#ff00ff\", \"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green / Amber\",\n          \"colors\": [\"#00ff00\", \"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber / Blue\",\n          \"colors\": [\"#ffbf00\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue / Cyan\",\n          \"colors\": [\"#0000ff\", \"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan / White\",\n          \"colors\": [\"#00ffff\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [64, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Red … Yellow … Magenta … Green … Amber … Blue … Cyan … White\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#ffffff\"],\n          \"helpWanted\": \"It would be helpful to split up this capability into individual ranges. At which DMX values are the full-color stops located?\"\n        },\n        {\n          \"dmxRange\": [192, 222],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [223, 224],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"PanTiltSpeed\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [4, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Effects Delay\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"Time\",\n          \"time\": \"instant\"\n        },\n        {\n          \"dmxRange\": [4, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Blackout Move\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"black out at pan/tilt moves\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"black out at color changing\"\n        },\n        {\n          \"dmxRange\": [160, 223],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"black out at color changes and pan/tilt moves. Dimmer fade\",\n          \"parameterStart\": \"slow\",\n          \"parameterEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard 8bit\",\n      \"shortName\": \"S8\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Control\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Pan/Tilt Speed\",\n        \"Effects Delay\",\n        \"Blackout Move\"\n      ]\n    },\n    {\n      \"name\": \"Standard 16bit\",\n      \"shortName\": \"S16\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Control\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Pan/Tilt Speed\",\n        \"Effects Delay\",\n        \"Blackout Move\"\n      ]\n    },\n    {\n      \"name\": \"Compressed 8bit\",\n      \"shortName\": \"C8\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Control\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"CTC\"\n      ]\n    },\n    {\n      \"name\": \"Compressed 16bit\",\n      \"shortName\": \"C16\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Control\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"CTC\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/jb-lighting/varyscan-p7.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Varyscan P7\",\n  \"shortName\": \"JBVaryscanP7\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-01-08\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"https://www.jb-lighting.de/download/Handbuch/Varyscan_P7_Manual.pdf\"],\n    \"video\": [\"https://www.youtube.com/watch?v=Xhadeddd1h8\"]\n  },\n  \"physical\": {\n    \"dimensions\": [380, 580, 264],\n    \"weight\": 17,\n    \"power\": 380,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"White light LED module 270W\",\n      \"lumens\": 11020\n    },\n    \"lens\": {\n      \"degreesMinMax\": [8, 48]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#0000aa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff88cc\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#ffd2b0\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"433.6deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"280deg\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 8,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer fade out with Fader (fast reaction)\",\n          \"parameterStart\": \"slow\",\n          \"parameterEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [8, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer fade out with Fader (semi-fast reaction)\",\n          \"parameterStart\": \"slow\",\n          \"parameterEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [40, 63],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer fade out with Fader (medium reaction)\",\n          \"parameterStart\": \"slow\",\n          \"parameterEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer fade out with Fader (semi-slow reaction)\",\n          \"parameterStart\": \"slow\",\n          \"parameterEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer fade out with Fader (slow reaction)\",\n          \"parameterStart\": \"slow\",\n          \"parameterEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [136, 207],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Camera mode, 50Hz\",\n          \"hold\": \"2s\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Camera mode, 60Hz\",\n          \"hold\": \"2s\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Camera mode, FLEX\",\n          \"hold\": \"2s\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Save\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"2s\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Save\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 16,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [96, 110],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \">20Hz\"\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [112, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dimmer fade effect\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"<20Hz\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [144, 158],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [160, 174],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Fade 0%\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [176, 190],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Fade 100%\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [192, 206],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"0%\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [208, 222],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"100%\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [224, 238],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Fade 0%\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 254],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Fade 100%\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"48deg\",\n        \"angleEnd\": \"8deg\"\n      }\n    },\n    \"Iris\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"open\",\n          \"openPercentEnd\": \"closed\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Opening pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [144, 158],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Closing pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [160, 174],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [176, 190],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [192, 206],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random opening pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [208, 222],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random closing pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [224, 238],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp down\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [240, 254],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp up\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        }\n      ]\n    },\n    \"Gobo Wheel 2 Position / Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Wheel 2 Position / Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [192, 222],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speed\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [2, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10.5\n        },\n        {\n          \"dmxRange\": [40, 63],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [64, 191],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"comment\": \"Colors linear, beginning from white\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"fineChannelAliases\": [\"Magenta fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"fineChannelAliases\": [\"Yellow fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Sparkle\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sparkle\",\n          \"parameterStart\": \"off\",\n          \"parameterEnd\": \"high\"\n        }\n      ]\n    },\n    \"Sparkle Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"EffectSpeed\",\n          \"comment\": \"Faded\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"EffectSpeed\",\n          \"comment\": \"Switched\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [64, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Repeat of fade and switch block\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Prism\"\n        }\n      ]\n    },\n    \"Prism Position / Rotation\": {\n      \"fineChannelAliases\": [\"Prism Position / Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [192, 222],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"off\",\n          \"frostIntensityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Opening pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"low\"\n        },\n        {\n          \"dmxRange\": [144, 158],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Closing pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        },\n        {\n          \"dmxRange\": [160, 174],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"low\"\n        },\n        {\n          \"dmxRange\": [176, 190],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        },\n        {\n          \"dmxRange\": [192, 206],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Random opening pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"low\"\n        },\n        {\n          \"dmxRange\": [208, 222],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Random closing pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        },\n        {\n          \"dmxRange\": [224, 238],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Random ramp up\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"low\"\n        },\n        {\n          \"dmxRange\": [240, 254],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Random ramp down\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aperture for logo projection\"\n        }\n      ]\n    },\n    \"Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 001-255\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [4, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [4, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Blackout on Move\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at pan/tilt\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at gobo, color, prism, CMY, iris, frost\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at gobo, color, prism, CMY, iris, frost, zoom, focus\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at gobo, color, prism, CMY, iris, frost, pan/tilt\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout at gobo, color, prism, CMY, iris, frost, zoom, focus, pan/tilt\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1st\",\n      \"shortName\": \"M1\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Control\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Focus\",\n        \"Zoom\",\n        \"Iris\",\n        \"Gobo Wheel 1\",\n        \"Gobo Wheel 2\",\n        \"Gobo Wheel 2 Position / Rotation\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Sparkle\",\n        \"Sparkle Speed\",\n        \"Prism\",\n        \"Prism Position / Rotation\",\n        \"Frost\",\n        \"Macro\",\n        \"Pan/Tilt Speed\",\n        \"Effect Speed\",\n        \"Blackout on Move\"\n      ]\n    },\n    {\n      \"name\": \"2nd\",\n      \"shortName\": \"M2\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Control\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Focus\",\n        \"Zoom\",\n        \"Iris\",\n        \"Gobo Wheel 1\",\n        \"Gobo Wheel 2\",\n        \"Gobo Wheel 2 Position / Rotation\",\n        \"Gobo Wheel 2 Position / Rotation fine\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\",\n        \"Sparkle\",\n        \"Sparkle Speed\",\n        \"Prism\",\n        \"Prism Position / Rotation\",\n        \"Prism Position / Rotation fine\",\n        \"Frost\",\n        \"Macro\",\n        \"Pan/Tilt Speed\",\n        \"Effect Speed\",\n        \"Blackout on Move\"\n      ]\n    },\n    {\n      \"name\": \"3rd\",\n      \"shortName\": \"M3\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Control\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Focus\",\n        \"Zoom\",\n        \"Iris\",\n        \"Gobo Wheel 1\",\n        \"Gobo Wheel 2\",\n        \"Gobo Wheel 2 Position / Rotation\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Sparkle\",\n        \"Sparkle Speed\",\n        \"Prism\",\n        \"Prism Position / Rotation\",\n        \"Frost\",\n        \"Macro\",\n        \"Blackout on Move\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/jb-systems/imove-5s.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"iMove 5S\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Duende AV\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-09-20\",\n    \"lastModifyDate\": \"2020-09-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://jb-systems.eu/fileuploader/download/download/?d=0&file=custom%2Fupload%2FFile-1437572496.pdf\"\n    ],\n    \"productPage\": [\n      \"https://jb-systems.eu/imove-5s-elc-250w-24v-incl\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=OQB-kBAp3eU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [290, 330, 380],\n    \"weight\": 12,\n    \"power\": 250,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"ELC 250W/24V\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [16, 16]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/10-circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Donut\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/biohazard\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Spider web\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"3 circling drops\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Sprinkles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Segmented square\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Radioactive\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Emblem\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"5-pointed star\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"5 dots row\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Segmented circle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Atomic orbits\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Cross pattern\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00c200\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#99ccff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV Purple\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#8aff8a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff8800\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff88ff\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Shutter / Shaking\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 247],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [26, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [35, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [44, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [52, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [60, 68],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [69, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [77, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [94, 102],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [103, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [111, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [22, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [32, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [43, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [54, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [64, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [75, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [96, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [107, 117],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Color Wheel Split\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 22],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [23, 30],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 37],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [46, 52],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [53, 60],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [61, 67],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [68, 75],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [76, 82],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [83, 90],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [98, 105],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 10.5\n        },\n        {\n          \"dmxRange\": [106, 112],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [113, 120],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 11.5\n        },\n        {\n          \"dmxRange\": [121, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Normal\",\n      \"shortName\": \"no\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Shutter / Shaking\",\n        \"Gobo Wheel\",\n        \"Color Wheel\"\n      ]\n    },\n    {\n      \"name\": \"Split Color\",\n      \"shortName\": \"SC\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Shutter / Shaking\",\n        \"Gobo Wheel\",\n        \"Color Wheel Split\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/jb-systems/irock-5c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"iRock 5C\",\n  \"categories\": [\"Effect\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Andres Robles\", \"Duende AV\", \"Flo Edelmann\"],\n    \"createDate\": \"2021-02-18\",\n    \"lastModifyDate\": \"2021-02-18\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2020-04-17\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.1 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/1117275/Jb-Systems-Irock-5c.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=1kusKMALR0w\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [340, 360, 250],\n    \"weight\": 9.2,\n    \"power\": 300,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"HSD 250W\",\n      \"colorTemperature\": 7200,\n      \"lumens\": 8600\n    },\n    \"lens\": {\n      \"name\": \"PC\",\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/10-circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Shattered\"\n        },\n        {\n          \"type\": \"Frost\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"3D Donut\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/glass-raindrops-on-window\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colorTemperature\": \"3200K\",\n          \"colors\": [\"#ffad32\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"colorTemperature\": \"5600K\",\n          \"colors\": [\"#ffd6a1\"]\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Green\",\n          \"colors\": [\"#005500\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Magenta\",\n          \"colors\": [\"#7f005f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#00aaff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff9100\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#00007f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#aa55ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#aaff7f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Magenta\",\n          \"colors\": [\"#fd78e7\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter/Shaking\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 247],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 22],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [23, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 52],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [53, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [68, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 82],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [83, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [98, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [113, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [121, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 120],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [135, 245],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"bright\",\n        \"brightnessEnd\": \"off\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Shutter/Shaking\",\n        \"Gobo Wheel\",\n        \"Color Wheel\",\n        \"Gobo Rotation\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/jb-systems/twin-effect-laser.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Twin Effect Laser\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Nerijus Mongirdas\", \"Flo Edelmann\"],\n    \"createDate\": \"2017-09-19\",\n    \"lastModifyDate\": \"2018-08-09\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2017-09-19\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.0)\"\n    }\n  },\n  \"comment\": \"40mW Green CW laser (λ = 532nm)\\n80mW Red CW laser (λ = 650nm)\\nLaser radiation class: 3B\",\n  \"links\": {\n    \"manual\": [\"https://www.manualslib.com/download/1126183/Jbsystems-Light-Twin-Effect.html\"],\n    \"video\": [\"https://www.youtube.com/watch?v=rCnrJEq-BV0\"]\n  },\n  \"physical\": {\n    \"dimensions\": [240, 110, 215],\n    \"weight\": 2.6,\n    \"power\": 28,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"laser-mode-1ch\": {\n      \"name\": \"Laser Mode\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [25, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUd mode (Auto grating effects show)\"\n        },\n        {\n          \"dmxRange\": [60, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUp mode (Auto pattern effects show)\"\n        },\n        {\n          \"dmxRange\": [100, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUn mode (Auto grating + pattern effects show)\"\n        },\n        {\n          \"dmxRange\": [140, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sod mode (Sound active grating effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [180, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"SoP mode (Sound active pattern effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Son mode (Sound active grating / pattern effects show)\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"laser-mode-10ch-combined\": {\n      \"name\": \"Laser Mode\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Laser off\",\n          \"switchChannels\": {\n            \"Channel 2\": \"Unused 1\",\n            \"Channel 3\": \"Unused 2\",\n            \"Channel 4\": \"Unused 3\",\n            \"Channel 5\": \"Unused 4\",\n            \"Channel 6\": \"Unused 5\",\n            \"Channel 7\": \"Unused 6\",\n            \"Channel 8\": \"Unused 7\",\n            \"Channel 9\": \"Unused 8\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUn mode (Auto grating + pattern effects show)\",\n          \"switchChannels\": {\n            \"Channel 2\": \"Unused 1\",\n            \"Channel 3\": \"Unused 2\",\n            \"Channel 4\": \"Unused 3\",\n            \"Channel 5\": \"Unused 4\",\n            \"Channel 6\": \"Unused 5\",\n            \"Channel 7\": \"Unused 6\",\n            \"Channel 8\": \"Unused 7\",\n            \"Channel 9\": \"Unused 8\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Son mode (Sound active grating / pattern effects show)\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Channel 2\": \"Unused 1\",\n            \"Channel 3\": \"Unused 2\",\n            \"Channel 4\": \"Unused 3\",\n            \"Channel 5\": \"Unused 4\",\n            \"Channel 6\": \"Unused 5\",\n            \"Channel 7\": \"Unused 6\",\n            \"Channel 8\": \"Unused 7\",\n            \"Channel 9\": \"Unused 8\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUP mode (Auto pattern effects show)\",\n          \"switchChannels\": {\n            \"Channel 2\": \"Unused 1\",\n            \"Channel 3\": \"Unused 2\",\n            \"Channel 4\": \"Unused 3\",\n            \"Channel 5\": \"Unused 4\",\n            \"Channel 6\": \"Unused 5\",\n            \"Channel 7\": \"Unused 6\",\n            \"Channel 8\": \"Unused 7\",\n            \"Channel 9\": \"Unused 8\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"SoP (Sound active pattern effects show)\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Channel 2\": \"Unused 1\",\n            \"Channel 3\": \"Unused 2\",\n            \"Channel 4\": \"Unused 3\",\n            \"Channel 5\": \"Unused 4\",\n            \"Channel 6\": \"Unused 5\",\n            \"Channel 7\": \"Unused 6\",\n            \"Channel 8\": \"Unused 7\",\n            \"Channel 9\": \"Unused 8\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUd mode (Auto grating effects show)\",\n          \"switchChannels\": {\n            \"Channel 2\": \"Unused 1\",\n            \"Channel 3\": \"Unused 2\",\n            \"Channel 4\": \"Unused 3\",\n            \"Channel 5\": \"Unused 4\",\n            \"Channel 6\": \"Unused 5\",\n            \"Channel 7\": \"Unused 6\",\n            \"Channel 8\": \"Unused 7\",\n            \"Channel 9\": \"Unused 8\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sod mode (Sound active grating effects show)\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Channel 2\": \"Unused 1\",\n            \"Channel 3\": \"Unused 2\",\n            \"Channel 4\": \"Unused 3\",\n            \"Channel 5\": \"Unused 4\",\n            \"Channel 6\": \"Unused 5\",\n            \"Channel 7\": \"Unused 6\",\n            \"Channel 8\": \"Unused 7\",\n            \"Channel 9\": \"Unused 8\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with Grating Dot effects\",\n          \"switchChannels\": {\n            \"Channel 2\": \"X Axis Moving\",\n            \"Channel 3\": \"Y Axis Moving\",\n            \"Channel 4\": \"colors-10ch-A\",\n            \"Channel 5\": \"Strobe\",\n            \"Channel 6\": \"grating-rotation-10ch-A\",\n            \"Channel 7\": \"Unused 6\",\n            \"Channel 8\": \"Unused 7\",\n            \"Channel 9\": \"Unused 8\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with Grating Pattern effects\",\n          \"switchChannels\": {\n            \"Channel 2\": \"Patterns\",\n            \"Channel 3\": \"Zooming\",\n            \"Channel 4\": \"Y Axis Rolling\",\n            \"Channel 5\": \"X Axis Rolling\",\n            \"Channel 6\": \"Z Axis Rolling\",\n            \"Channel 7\": \"X Axis Moving\",\n            \"Channel 8\": \"Y Axis Moving\",\n            \"Channel 9\": \"colors-10ch-B\",\n            \"Channel 10\": \"grating-rotation-10ch-B\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with traditional pattern effects\",\n          \"switchChannels\": {\n            \"Channel 2\": \"Patterns\",\n            \"Channel 3\": \"Zooming\",\n            \"Channel 4\": \"Y Axis Rolling\",\n            \"Channel 5\": \"X Axis Rolling\",\n            \"Channel 6\": \"Z Axis Rolling\",\n            \"Channel 7\": \"X Axis Moving\",\n            \"Channel 8\": \"Y Axis Moving\",\n            \"Channel 9\": \"colors-10ch-C\",\n            \"Channel 10\": \"Unused 9\"\n          }\n        }\n      ]\n    },\n    \"laser-mode-10ch-A\": {\n      \"name\": \"Laser Mode\",\n      \"defaultValue\": 175,\n      \"constant\": true,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUn mode (Auto grating + pattern effects show)\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Son mode (Sound active grating / pattern effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUP mode (Auto pattern effects show)\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"SoP (Sound active pattern effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUd mode (Auto grating effects show)\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sod mode (Sound active grating effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with Grating Dot effects\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with Grating Pattern effects\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with traditional pattern effects\"\n        }\n      ]\n    },\n    \"laser-mode-10ch-B\": {\n      \"name\": \"Laser Mode\",\n      \"defaultValue\": 200,\n      \"constant\": true,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUn mode (Auto grating + pattern effects show)\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Son mode (Sound active grating / pattern effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUP mode (Auto pattern effects show)\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"SoP (Sound active pattern effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUd mode (Auto grating effects show)\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sod mode (Sound active grating effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with Grating Dot effects\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with Grating Pattern effects\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with traditional pattern effects\"\n        }\n      ]\n    },\n    \"laser-mode-10ch-C\": {\n      \"name\": \"Laser Mode\",\n      \"defaultValue\": 225,\n      \"constant\": true,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUn mode (Auto grating + pattern effects show)\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Son mode (Sound active grating / pattern effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUP mode (Auto pattern effects show)\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"SoP (Sound active pattern effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"AUd mode (Auto grating effects show)\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sod mode (Sound active grating effects show)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with Grating Dot effects\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with Grating Pattern effects\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX mode with traditional pattern effects\"\n        }\n      ]\n    },\n    \"X Axis Moving\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"0%\",\n          \"horizontalAngleEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Y Axis Moving\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"0%\",\n          \"verticalAngleEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"X Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"359deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Y Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"359deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Z Axis Rolling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"359deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CCW\"\n        }\n      ]\n    },\n    \"colors-10ch-A\": {\n      \"name\": \"Colors\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Laser blackout\"\n        },\n        {\n          \"dmxRange\": [10, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red & green on OR red & green strobing\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red on OR red strobing\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green on OR green strobing\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red & green on OR red & green strobing alternately\"\n        }\n      ]\n    },\n    \"colors-10ch-B\": {\n      \"name\": \"Colors\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [17, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [32, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Red & Green\"\n        },\n        {\n          \"dmxRange\": [50, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        }\n      ]\n    },\n    \"colors-10ch-C\": {\n      \"name\": \"Colors\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Original colors\"\n        },\n        {\n          \"dmxRange\": [17, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 62],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Red + Green (Yellow)\"\n        },\n        {\n          \"dmxRange\": [63, 160],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Red / Green alternating\"\n        },\n        {\n          \"dmxRange\": [161, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Changing mix of 3 colors\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Strobing\"\n        },\n        {\n          \"dmxRange\": [10, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"grating-rotation-10ch-A\": {\n      \"name\": \"Grating Rotation\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 75],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [76, 150],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"grating-rotation-10ch-B\": {\n      \"name\": \"Grating Rotation\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 75],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [76, 150],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Patterns\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"11 different grating patterns\",\n        \"helpWanted\": \"Which patterns can be selected at which DMX values?\"\n      }\n    },\n    \"Zooming\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Zoom\",\n          \"angleStart\": \"wide\",\n          \"angleEnd\": \"narrow\",\n          \"comment\": \"Pattern size\"\n        },\n        {\n          \"dmxRange\": [128, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zooming in\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"parameterStart\": \"big\",\n          \"parameterEnd\": \"small\"\n        },\n        {\n          \"dmxRange\": [170, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zooming out\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"parameterStart\": \"big\",\n          \"parameterEnd\": \"small\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"Effect\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"effectName\": \"Zooming in & out\"\n        }\n      ]\n    },\n    \"Unused 1\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 2\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 3\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 4\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 5\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 6\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 7\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 8\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Unused 9\": {\n      \"name\": \"Unused\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"laser-mode-1ch\"\n      ]\n    },\n    {\n      \"name\": \"10-channel combined\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"laser-mode-10ch-combined\",\n        \"Channel 2\",\n        \"Channel 3\",\n        \"Channel 4\",\n        \"Channel 5\",\n        \"Channel 6\",\n        \"Channel 7\",\n        \"Channel 8\",\n        \"Channel 9\",\n        \"Channel 10\"\n      ]\n    },\n    {\n      \"name\": \"10-channel grating dot\",\n      \"shortName\": \"10ch-A\",\n      \"channels\": [\n        \"laser-mode-10ch-A\",\n        \"X Axis Moving\",\n        \"Y Axis Moving\",\n        \"colors-10ch-A\",\n        \"Strobe\",\n        \"grating-rotation-10ch-A\",\n        null,\n        null,\n        null,\n        null\n      ]\n    },\n    {\n      \"name\": \"10-channel grating pattern\",\n      \"shortName\": \"10ch-B\",\n      \"channels\": [\n        \"laser-mode-10ch-B\",\n        \"Patterns\",\n        \"Zooming\",\n        \"Y Axis Rolling\",\n        \"X Axis Rolling\",\n        \"Z Axis Rolling\",\n        \"X Axis Moving\",\n        \"Y Axis Moving\",\n        \"colors-10ch-B\",\n        \"grating-rotation-10ch-B\"\n      ]\n    },\n    {\n      \"name\": \"10-channel traditional pattern\",\n      \"shortName\": \"10ch-C\",\n      \"channels\": [\n        \"laser-mode-10ch-C\",\n        \"Patterns\",\n        \"Zooming\",\n        \"Y Axis Rolling\",\n        \"X Axis Rolling\",\n        \"Z Axis Rolling\",\n        \"X Axis Moving\",\n        \"Y Axis Moving\",\n        \"colors-10ch-C\",\n        null\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/kam/gobotracer.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"GoboTracer\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Justin Hornsby\"],\n    \"createDate\": \"2017-11-16\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ZW2WMacskD0\"\n    ]\n  },\n  \"physical\": {\n    \"DMXconnector\": \"3-pin\",\n    \"dimensions\": [210, 285, 147],\n    \"weight\": 3.2,\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"comment\": \"Color scroll\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 8,\n          \"helpWanted\": \"Which gobos can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"stop\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Horizontal Vertical Run\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"helpWanted\": \"What is this channel for?\"\n      }\n    },\n    \"Auto Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Other channels on\"\n        },\n        {\n          \"dmxRange\": [60, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode 3\"\n        },\n        {\n          \"dmxRange\": [85, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode 2\"\n        },\n        {\n          \"dmxRange\": [110, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode 1\"\n        },\n        {\n          \"dmxRange\": [135, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-to-light mode 0\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-to-light mode 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [185, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-to-light mode 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [210, 234],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-to-light mode 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [235, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-to-light mode 0\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"5s\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Horizontal Vertical Run\",\n        \"Auto Mode\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Horizontal Vertical Run\",\n        \"Auto Mode\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/kino-flo/celeb-250-led-dmx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Celeb 250 LED DMX\",\n  \"shortName\": \"Celeb 250\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2022-05-07\",\n    \"lastModifyDate\": \"2022-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.kinoflotest2.com/PDF/News/Operational%20Manual%20for%20the%20web/3100105%20Rev%20A%20Celeb%C2%AE%20250-450-450@%20LED%20DMX%2008-10-2017.pdf\",\n      \"https://www.kinoflotest2.com/PDF/True%20Match%20Firmware%204.0/True%20Match%20Firmware%205.0%20RDM%20DMX%20Personalities%20May%202021.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.kinoflotest2.com/Products%20Button/LED/Celeb%20250%20DMX/Celeb_250_DMX.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=O_970WxLhdo\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 257,\n    \"softwareVersion\": \"5.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [610, 360, 130],\n    \"weight\": 6.8,\n    \"power\": 144,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Tungsten\": {\n      \"fineChannelAliases\": [\"Tungsten fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"comment\": \"Tungsten\"\n      }\n    },\n    \"Daylight\": {\n      \"fineChannelAliases\": [\"Daylight fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"comment\": \"Daylight\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2500K\",\n        \"colorTemperatureEnd\": \"9900K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2500K\",\n        \"colorTemperatureEnd\": \"9900K\"\n      }\n    },\n    \"Gel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Candle Flame\",\n          \"colors\": [\"#fc8004\"]\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Flo Warm White\",\n          \"colors\": [\"#ffffcc\"]\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Flo Cool White\",\n          \"colors\": [\"#ccffff\"]\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF LP Sodium Vpr\",\n          \"colors\": [\"#ff9933\"]\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Mercury Vpr\",\n          \"colors\": [\"#ccccff\"]\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF 20K Blue Sky\",\n          \"colors\": [\"#9bc2e6\"]\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Green Screen\",\n          \"colors\": [\"#92d050\"]\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Blue Screen\",\n          \"colors\": [\"#0070c0\"]\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\",\n          \"colors\": [\"#ff99cc\"]\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\",\n          \"colors\": [\"#cc00ff\"]\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\",\n          \"colors\": [\"#ff33cc\"]\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\",\n          \"colors\": [\"#ff66cc\"]\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\",\n          \"colors\": [\"#ff6699\"]\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\",\n          \"colors\": [\"#ff9999\"]\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff66cc\"]\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rosy Amber\",\n          \"colors\": [\"#ff7c80\"]\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Red\",\n          \"colors\": [\"#ff5050\"]\n        },\n        {\n          \"dmxRange\": [40, 41],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\",\n          \"colors\": [\"#ff3300\"]\n        },\n        {\n          \"dmxRange\": [42, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\",\n          \"colors\": [\"#ff9933\"]\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\",\n          \"colors\": [\"#ff7c80\"]\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\",\n          \"colors\": [\"#ff5050\"]\n        },\n        {\n          \"dmxRange\": [48, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\",\n          \"colors\": [\"#ffcc00\"]\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"M Bastard Amber\",\n          \"colors\": [\"#ffcc99\"]\n        },\n        {\n          \"dmxRange\": [52, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\",\n          \"colors\": [\"#ff3300\"]\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\",\n          \"colors\": [\"#ff6600\"]\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff5050\"]\n        },\n        {\n          \"dmxRange\": [60, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\",\n          \"colors\": [\"#f96435\"]\n        },\n        {\n          \"dmxRange\": [62, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\",\n          \"colors\": [\"#f95427\"]\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\",\n          \"colors\": [\"#ee6612\"]\n        },\n        {\n          \"dmxRange\": [66, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\",\n          \"colors\": [\"#f0b31c\"]\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\",\n          \"colors\": [\"#f68276\"]\n        },\n        {\n          \"dmxRange\": [70, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\",\n          \"colors\": [\"#f3a25f\"]\n        },\n        {\n          \"dmxRange\": [72, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\",\n          \"colors\": [\"#f4ae74\"]\n        },\n        {\n          \"dmxRange\": [74, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Gld Amber\",\n          \"colors\": [\"#f8a714\"]\n        },\n        {\n          \"dmxRange\": [76, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\",\n          \"colors\": [\"#f3c003\"]\n        },\n        {\n          \"dmxRange\": [78, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\",\n          \"colors\": [\"#f98545\"]\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\",\n          \"colors\": [\"#f98545\"]\n        },\n        {\n          \"dmxRange\": [82, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\",\n          \"colors\": [\"#fecaba\"]\n        },\n        {\n          \"dmxRange\": [84, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\",\n          \"colors\": [\"#ef7903\"]\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\",\n          \"colors\": [\"#bb6209\"]\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#e55809\"]\n        },\n        {\n          \"dmxRange\": [90, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Flame\",\n          \"colors\": [\"#f0fed2\"]\n        },\n        {\n          \"dmxRange\": [92, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\",\n          \"colors\": [\"#f9cf59\"]\n        },\n        {\n          \"dmxRange\": [94, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\",\n          \"colors\": [\"#f7d36d\"]\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\",\n          \"colors\": [\"#fd8c4d\"]\n        },\n        {\n          \"dmxRange\": [98, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\",\n          \"colors\": [\"#fafcaa\"]\n        },\n        {\n          \"dmxRange\": [100, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\",\n          \"colors\": [\"#fffc79\"]\n        },\n        {\n          \"dmxRange\": [102, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\",\n          \"colors\": [\"#f6f000\"]\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\",\n          \"colors\": [\"#f3c003\"]\n        },\n        {\n          \"dmxRange\": [106, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\",\n          \"colors\": [\"#fddb5f\"]\n        },\n        {\n          \"dmxRange\": [108, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#fffb37\"]\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\",\n          \"colors\": [\"#fdfda1\"]\n        },\n        {\n          \"dmxRange\": [112, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\",\n          \"colors\": [\"#ffff66\"]\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\",\n          \"colors\": [\"#fdfda1\"]\n        },\n        {\n          \"dmxRange\": [116, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\",\n          \"colors\": [\"#8ffc0c\"]\n        },\n        {\n          \"dmxRange\": [118, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\",\n          \"colors\": [\"#b9fd67\"]\n        },\n        {\n          \"dmxRange\": [120, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Leaf Green\",\n          \"colors\": [\"#92d050\"]\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\",\n          \"colors\": [\"#00cc66\"]\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\",\n          \"colors\": [\"#05fc10\"]\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Y Green\",\n          \"colors\": [\"#91fb03\"]\n        },\n        {\n          \"dmxRange\": [130, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\",\n          \"colors\": [\"#03df03\"]\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\",\n          \"colors\": [\"#4088fe\"]\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\",\n          \"colors\": [\"#0099ff\"]\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Med Blue-Green\",\n          \"colors\": [\"#3399ff\"]\n        },\n        {\n          \"dmxRange\": [138, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sp Steel Blue\",\n          \"colors\": [\"#89c4ff\"]\n        },\n        {\n          \"dmxRange\": [140, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\",\n          \"colors\": [\"#4bd1fb\"]\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\",\n          \"colors\": [\"#c1e0ff\"]\n        },\n        {\n          \"dmxRange\": [144, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter Blue\",\n          \"colors\": [\"#c1eaff\"]\n        },\n        {\n          \"dmxRange\": [146, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\",\n          \"colors\": [\"#92d6f8\"]\n        },\n        {\n          \"dmxRange\": [148, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#c1e0ff\"]\n        },\n        {\n          \"dmxRange\": [150, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\",\n          \"colors\": [\"#3a7bfc\"]\n        },\n        {\n          \"dmxRange\": [152, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\",\n          \"colors\": [\"#aec1fc\"]\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\",\n          \"colors\": [\"#6387f9\"]\n        },\n        {\n          \"dmxRange\": [156, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\",\n          \"colors\": [\"#99ccff\"]\n        },\n        {\n          \"dmxRange\": [158, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\",\n          \"colors\": [\"#0066cc\"]\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\",\n          \"colors\": [\"#2190ff\"]\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\",\n          \"colors\": [\"#2994ff\"]\n        },\n        {\n          \"dmxRange\": [164, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\",\n          \"colors\": [\"#99ccff\"]\n        },\n        {\n          \"dmxRange\": [166, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\",\n          \"colors\": [\"#006f6c\"]\n        },\n        {\n          \"dmxRange\": [168, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\",\n          \"colors\": [\"#2994ff\"]\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#5badff\"]\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\",\n          \"colors\": [\"#acaefe\"]\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\",\n          \"colors\": [\"#7b7efd\"]\n        },\n        {\n          \"dmxRange\": [176, 177],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\",\n          \"colors\": [\"#8859fd\"]\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\",\n          \"colors\": [\"#af83fd\"]\n        },\n        {\n          \"dmxRange\": [180, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\",\n          \"colors\": [\"#7c58fe\"]\n        },\n        {\n          \"dmxRange\": [182, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Violet\",\n          \"colors\": [\"#9b39fd\"]\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\",\n          \"colors\": [\"#5c41fd\"]\n        },\n        {\n          \"dmxRange\": [186, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\",\n          \"colors\": [\"#fb6efe\"]\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\",\n          \"colors\": [\"#2b08fc\"]\n        },\n        {\n          \"dmxRange\": [190, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special M Blue\",\n          \"colors\": [\"#745dfd\"]\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\",\n          \"colors\": [\"#b694fa\"]\n        },\n        {\n          \"dmxRange\": [194, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\",\n          \"colors\": [\"#cdb6fc\"]\n        },\n        {\n          \"dmxRange\": [196, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\",\n          \"colors\": [\"#745dfd\"]\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\",\n          \"colors\": [\"#d77def\"]\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\",\n          \"colors\": [\"#5c41fd\"]\n        },\n        {\n          \"dmxRange\": [202, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\",\n          \"colors\": [\"#ba35ef\"]\n        },\n        {\n          \"dmxRange\": [204, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\",\n          \"colors\": [\"#d37ff5\"]\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\",\n          \"colors\": [\"#a011d9\"]\n        },\n        {\n          \"dmxRange\": [208, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#a011d9\"]\n        },\n        {\n          \"dmxRange\": [210, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\",\n          \"colors\": [\"#780da3\"]\n        },\n        {\n          \"dmxRange\": [212, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\",\n          \"colors\": [\"#471aee\"]\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\",\n          \"colors\": [\"#da10d0\"]\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#f0346a\"]\n        },\n        {\n          \"dmxRange\": [218, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\",\n          \"colors\": [\"#f35b86\"]\n        },\n        {\n          \"dmxRange\": [220, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Follies Pink\",\n          \"colors\": [\"#f46c93\"]\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\",\n          \"colors\": [\"#f2548c\"]\n        },\n        {\n          \"dmxRange\": [224, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\",\n          \"colors\": [\"#f577a4\"]\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\",\n          \"colors\": [\"#f8a6c3\"]\n        },\n        {\n          \"dmxRange\": [228, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#fcd4e2\"]\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\",\n          \"colors\": [\"#f2548c\"]\n        },\n        {\n          \"dmxRange\": [232, 233],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\",\n          \"colors\": [\"#fdd3d3\"]\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Green-Magenta Point\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Candle\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scroll\"\n        },\n        {\n          \"dmxRange\": [90, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"FX Param 1\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"FX Param 2\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"FX Param 3\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"FX Param 4\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"FX Param 5\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"CIE x\": {\n      \"fineChannelAliases\": [\"CIE x fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…0.85\"\n      }\n    },\n    \"CIE y\": {\n      \"fineChannelAliases\": [\"CIE y fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…0.85\"\n      }\n    },\n    \"CIE x2\": {\n      \"fineChannelAliases\": [\"CIE x2 fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…0.85\"\n      }\n    },\n    \"CIE y2\": {\n      \"fineChannelAliases\": [\"CIE y2 fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…0.85\"\n      }\n    },\n    \"Crossfade\": {\n      \"fineChannelAliases\": [\"Crossfade fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"CCT … Color Mix\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P1 DIMMING & CCT\",\n      \"shortName\": \"P1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"P2 HSI + CCT, Gel 8bit\",\n      \"shortName\": \"P2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Gel\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P3 CCT, RGB 8bit\",\n      \"shortName\": \"P3\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P4 FX 8bit\",\n      \"shortName\": \"P4\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Effect\",\n        \"Color Temperature\",\n        \"FX Param 1\",\n        \"FX Param 2\",\n        \"FX Param 3\",\n        \"FX Param 4\",\n        \"FX Param 5\"\n      ]\n    },\n    {\n      \"name\": \"P5 CIE xy 8bit\",\n      \"shortName\": \"P5\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CIE x\",\n        \"CIE y\"\n      ]\n    },\n    {\n      \"name\": \"P6 CCT 16bit\",\n      \"shortName\": \"P6\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"P7 HSI & CCT, Gel 16bit\",\n      \"shortName\": \"P7\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Gel\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P8 CCT, RGB 16bit\",\n      \"shortName\": \"P8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P9 FX 16bit\",\n      \"shortName\": \"P9\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Effect\",\n        \"Color Temperature\",\n        \"FX Param 1\",\n        \"FX Param 2\",\n        \"FX Param 3\",\n        \"FX Param 4\",\n        \"FX Param 5\"\n      ]\n    },\n    {\n      \"name\": \"P10 CIE xy 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CIE x\",\n        \"CIE y\"\n      ]\n    },\n    {\n      \"name\": \"P11 CCT 8bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"P12 CCT 16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"P13 Gel 8bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Gel\"\n      ]\n    },\n    {\n      \"name\": \"P14 Gel 16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Gel\"\n      ]\n    },\n    {\n      \"name\": \"P15 HSI & CCT 8bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P16 HSI & CCT 16bit\",\n      \"shortName\": \"P16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P17 RGB & CCT 8bit\",\n      \"shortName\": \"P17\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P18 RGB & CCT 16bit\",\n      \"shortName\": \"P18\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    },\n    {\n      \"name\": \"P19 CIE xy 8bit\",\n      \"shortName\": \"P19\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CIE x\",\n        \"CIE y\"\n      ]\n    },\n    {\n      \"name\": \"P20 CIE xy 16bit\",\n      \"shortName\": \"P20\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CIE x\",\n        \"CIE x fine\",\n        \"CIE y\",\n        \"CIE y fine\"\n      ]\n    },\n    {\n      \"name\": \"P21 FX 8bit\",\n      \"shortName\": \"P21\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Effect\",\n        \"Color Temperature\",\n        \"FX Param 1\",\n        \"FX Param 2\",\n        \"FX Param 3\",\n        \"FX Param 4\",\n        \"FX Param 5\"\n      ]\n    },\n    {\n      \"name\": \"P22 FX 16bit\",\n      \"shortName\": \"P22\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Effect\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"FX Param 1\",\n        \"FX Param 2\",\n        \"FX Param 3\",\n        \"FX Param 4\",\n        \"FX Param 5\"\n      ]\n    },\n    {\n      \"name\": \"P23 xfade CCT & HSI 8bit\",\n      \"shortName\": \"P23\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Color Temperature 2\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P24 xfade CCT & HSI 16bit\",\n      \"shortName\": \"P24\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P25 xfade CCT & RBG 8bit\",\n      \"shortName\": \"P25\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Color Temperature 2\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P26 xfade CCT & RBG 16bit\",\n      \"shortName\": \"P26\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    },\n    {\n      \"name\": \"P27 xfade CIE xy1 & CIE xy2 8bit\",\n      \"shortName\": \"P27\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CIE x\",\n        \"CIE y\",\n        \"Crossfade\",\n        \"CIE x2\",\n        \"CIE y2\"\n      ]\n    },\n    {\n      \"name\": \"P28 xfade CIE xy1 & CIE xy2 16bit\",\n      \"shortName\": \"P28\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CIE x\",\n        \"CIE x fine\",\n        \"CIE y\",\n        \"CIE y fine\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"CIE x2\",\n        \"CIE x2 fine\",\n        \"CIE y2\",\n        \"CIE y2 fine\"\n      ]\n    },\n    {\n      \"name\": \"P29 xfade CCT & TDRGB 8bit\",\n      \"shortName\": \"P29\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Tungsten\",\n        \"Daylight\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P30 xfade CCT & TDRGB 16bit\",\n      \"shortName\": \"P30\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Tungsten\",\n        \"Tungsten fine\",\n        \"Daylight\",\n        \"Daylight fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/kino-flo/celeb-450-led-dmx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Celeb 450 LED DMX\",\n  \"shortName\": \"Celeb 450\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2022-05-07\",\n    \"lastModifyDate\": \"2022-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.kinoflotest2.com/PDF/News/Operational%20Manual%20for%20the%20web/3100105%20Rev%20A%20Celeb%C2%AE%20250-450-450@%20LED%20DMX%2008-10-2017.pdf\",\n      \"https://www.kinoflotest2.com/PDF/True%20Match%20Firmware%204.0/True%20Match%20Firmware%205.0%20RDM%20DMX%20Personalities%20May%202021.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.kinoflotest2.com/Products%20Button/LED/Celeb%20450%20DMX/Celeb_450_DMX.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=WIFVkzYkArE\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 258,\n    \"softwareVersion\": \"5.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [1145, 360, 130],\n    \"weight\": 12,\n    \"power\": 300,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Tungsten\": {\n      \"fineChannelAliases\": [\"Tungsten fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"comment\": \"Tungsten\"\n      }\n    },\n    \"Daylight\": {\n      \"fineChannelAliases\": [\"Daylight fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"comment\": \"Daylight\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2500K\",\n        \"colorTemperatureEnd\": \"9900K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2500K\",\n        \"colorTemperatureEnd\": \"9900K\"\n      }\n    },\n    \"Gel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Candle Flame\",\n          \"colors\": [\"#fc8004\"]\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Flo Warm White\",\n          \"colors\": [\"#ffffcc\"]\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Flo Cool White\",\n          \"colors\": [\"#ccffff\"]\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF LP Sodium Vpr\",\n          \"colors\": [\"#ff9933\"]\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Mercury Vpr\",\n          \"colors\": [\"#ccccff\"]\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF 20K Blue Sky\",\n          \"colors\": [\"#9bc2e6\"]\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Green Screen\",\n          \"colors\": [\"#92d050\"]\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"KF Blue Screen\",\n          \"colors\": [\"#0070c0\"]\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Smokey Pink\",\n          \"colors\": [\"#ff99cc\"]\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Magenta\",\n          \"colors\": [\"#cc00ff\"]\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Rose\",\n          \"colors\": [\"#ff33cc\"]\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Salmon\",\n          \"colors\": [\"#ff66cc\"]\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Rose\",\n          \"colors\": [\"#ff6699\"]\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Salmon\",\n          \"colors\": [\"#ff9999\"]\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff66cc\"]\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rosy Amber\",\n          \"colors\": [\"#ff7c80\"]\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Red\",\n          \"colors\": [\"#ff5050\"]\n        },\n        {\n          \"dmxRange\": [40, 41],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Scarlet\",\n          \"colors\": [\"#ff3300\"]\n        },\n        {\n          \"dmxRange\": [42, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Loving Amber\",\n          \"colors\": [\"#ff9933\"]\n        },\n        {\n          \"dmxRange\": [44, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Rose\",\n          \"colors\": [\"#ff7c80\"]\n        },\n        {\n          \"dmxRange\": [46, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Red\",\n          \"colors\": [\"#ff5050\"]\n        },\n        {\n          \"dmxRange\": [48, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Tint\",\n          \"colors\": [\"#ffcc00\"]\n        },\n        {\n          \"dmxRange\": [50, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"M Bastard Amber\",\n          \"colors\": [\"#ffcc99\"]\n        },\n        {\n          \"dmxRange\": [52, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Red\",\n          \"colors\": [\"#ff3300\"]\n        },\n        {\n          \"dmxRange\": [54, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flame Red\",\n          \"colors\": [\"#ff6600\"]\n        },\n        {\n          \"dmxRange\": [56, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [58, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ff5050\"]\n        },\n        {\n          \"dmxRange\": [60, 61],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Salmon\",\n          \"colors\": [\"#f96435\"]\n        },\n        {\n          \"dmxRange\": [62, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fire\",\n          \"colors\": [\"#f95427\"]\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sunset Red\",\n          \"colors\": [\"#ee6612\"]\n        },\n        {\n          \"dmxRange\": [66, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Gold\",\n          \"colors\": [\"#f0b31c\"]\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"English Rose\",\n          \"colors\": [\"#f68276\"]\n        },\n        {\n          \"dmxRange\": [70, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bastard Amber\",\n          \"colors\": [\"#f3a25f\"]\n        },\n        {\n          \"dmxRange\": [72, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Peach\",\n          \"colors\": [\"#f4ae74\"]\n        },\n        {\n          \"dmxRange\": [74, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Gld Amber\",\n          \"colors\": [\"#f8a714\"]\n        },\n        {\n          \"dmxRange\": [76, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Amber\",\n          \"colors\": [\"#f3c003\"]\n        },\n        {\n          \"dmxRange\": [78, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Apricot\",\n          \"colors\": [\"#f98545\"]\n        },\n        {\n          \"dmxRange\": [80, 81],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold Amber\",\n          \"colors\": [\"#f98545\"]\n        },\n        {\n          \"dmxRange\": [82, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cosmetic Peach\",\n          \"colors\": [\"#fecaba\"]\n        },\n        {\n          \"dmxRange\": [84, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Orange\",\n          \"colors\": [\"#ef7903\"]\n        },\n        {\n          \"dmxRange\": [86, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chocolate\",\n          \"colors\": [\"#bb6209\"]\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#e55809\"]\n        },\n        {\n          \"dmxRange\": [90, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Flame\",\n          \"colors\": [\"#f0fed2\"]\n        },\n        {\n          \"dmxRange\": [92, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Amber\",\n          \"colors\": [\"#f9cf59\"]\n        },\n        {\n          \"dmxRange\": [94, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Amber Gold\",\n          \"colors\": [\"#f7d36d\"]\n        },\n        {\n          \"dmxRange\": [96, 97],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Orange\",\n          \"colors\": [\"#fd8c4d\"]\n        },\n        {\n          \"dmxRange\": [98, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw Tint\",\n          \"colors\": [\"#fafcaa\"]\n        },\n        {\n          \"dmxRange\": [100, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Straw\",\n          \"colors\": [\"#fffc79\"]\n        },\n        {\n          \"dmxRange\": [102, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Straw\",\n          \"colors\": [\"#f6f000\"]\n        },\n        {\n          \"dmxRange\": [104, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Amber\",\n          \"colors\": [\"#f3c003\"]\n        },\n        {\n          \"dmxRange\": [106, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Amber\",\n          \"colors\": [\"#fddb5f\"]\n        },\n        {\n          \"dmxRange\": [108, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#fffb37\"]\n        },\n        {\n          \"dmxRange\": [110, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Yellow\",\n          \"colors\": [\"#fdfda1\"]\n        },\n        {\n          \"dmxRange\": [112, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Yellow\",\n          \"colors\": [\"#ffff66\"]\n        },\n        {\n          \"dmxRange\": [114, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Yellow\",\n          \"colors\": [\"#fdfda1\"]\n        },\n        {\n          \"dmxRange\": [116, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green\",\n          \"colors\": [\"#8ffc0c\"]\n        },\n        {\n          \"dmxRange\": [118, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Green\",\n          \"colors\": [\"#b9fd67\"]\n        },\n        {\n          \"dmxRange\": [120, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Leaf Green\",\n          \"colors\": [\"#92d050\"]\n        },\n        {\n          \"dmxRange\": [122, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fern Green\",\n          \"colors\": [\"#00cc66\"]\n        },\n        {\n          \"dmxRange\": [124, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Primary Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moss Green\",\n          \"colors\": [\"#05fc10\"]\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Y Green\",\n          \"colors\": [\"#91fb03\"]\n        },\n        {\n          \"dmxRange\": [130, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Green\",\n          \"colors\": [\"#03df03\"]\n        },\n        {\n          \"dmxRange\": [132, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Marine Blue\",\n          \"colors\": [\"#4088fe\"]\n        },\n        {\n          \"dmxRange\": [134, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Peacock Blue\",\n          \"colors\": [\"#0099ff\"]\n        },\n        {\n          \"dmxRange\": [136, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Med Blue-Green\",\n          \"colors\": [\"#3399ff\"]\n        },\n        {\n          \"dmxRange\": [138, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sp Steel Blue\",\n          \"colors\": [\"#89c4ff\"]\n        },\n        {\n          \"dmxRange\": [140, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lagoon Blue\",\n          \"colors\": [\"#4bd1fb\"]\n        },\n        {\n          \"dmxRange\": [142, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Steel Blue\",\n          \"colors\": [\"#c1e0ff\"]\n        },\n        {\n          \"dmxRange\": [144, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter Blue\",\n          \"colors\": [\"#c1eaff\"]\n        },\n        {\n          \"dmxRange\": [146, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Blue\",\n          \"colors\": [\"#92d6f8\"]\n        },\n        {\n          \"dmxRange\": [148, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#c1e0ff\"]\n        },\n        {\n          \"dmxRange\": [150, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Moonlight Blue\",\n          \"colors\": [\"#3a7bfc\"]\n        },\n        {\n          \"dmxRange\": [152, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Blue\",\n          \"colors\": [\"#aec1fc\"]\n        },\n        {\n          \"dmxRange\": [154, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Navy Blue\",\n          \"colors\": [\"#6387f9\"]\n        },\n        {\n          \"dmxRange\": [156, 157],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mist Blue\",\n          \"colors\": [\"#99ccff\"]\n        },\n        {\n          \"dmxRange\": [158, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Blue\",\n          \"colors\": [\"#0066cc\"]\n        },\n        {\n          \"dmxRange\": [160, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"True Blue\",\n          \"colors\": [\"#2190ff\"]\n        },\n        {\n          \"dmxRange\": [162, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Steel Blue\",\n          \"colors\": [\"#2994ff\"]\n        },\n        {\n          \"dmxRange\": [164, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Daylight Blue\",\n          \"colors\": [\"#99ccff\"]\n        },\n        {\n          \"dmxRange\": [166, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Slate Blue\",\n          \"colors\": [\"#006f6c\"]\n        },\n        {\n          \"dmxRange\": [168, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Blue\",\n          \"colors\": [\"#2994ff\"]\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#5badff\"]\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Paler Lavender\",\n          \"colors\": [\"#acaefe\"]\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Alice Blue\",\n          \"colors\": [\"#7b7efd\"]\n        },\n        {\n          \"dmxRange\": [176, 177],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special Lavender\",\n          \"colors\": [\"#8859fd\"]\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Violet\",\n          \"colors\": [\"#af83fd\"]\n        },\n        {\n          \"dmxRange\": [180, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Just Blue\",\n          \"colors\": [\"#7c58fe\"]\n        },\n        {\n          \"dmxRange\": [182, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Violet\",\n          \"colors\": [\"#9b39fd\"]\n        },\n        {\n          \"dmxRange\": [184, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Blue\",\n          \"colors\": [\"#5c41fd\"]\n        },\n        {\n          \"dmxRange\": [186, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Surprise Pink\",\n          \"colors\": [\"#fb6efe\"]\n        },\n        {\n          \"dmxRange\": [188, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deeper Blue\",\n          \"colors\": [\"#2b08fc\"]\n        },\n        {\n          \"dmxRange\": [190, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Special M Blue\",\n          \"colors\": [\"#745dfd\"]\n        },\n        {\n          \"dmxRange\": [192, 193],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Zenith Blue\",\n          \"colors\": [\"#b694fa\"]\n        },\n        {\n          \"dmxRange\": [194, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Lavender\",\n          \"colors\": [\"#cdb6fc\"]\n        },\n        {\n          \"dmxRange\": [196, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palace Blue\",\n          \"colors\": [\"#745dfd\"]\n        },\n        {\n          \"dmxRange\": [198, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac Tint\",\n          \"colors\": [\"#d77def\"]\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Blue\",\n          \"colors\": [\"#5c41fd\"]\n        },\n        {\n          \"dmxRange\": [202, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender Tint\",\n          \"colors\": [\"#ba35ef\"]\n        },\n        {\n          \"dmxRange\": [204, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pale Lavender\",\n          \"colors\": [\"#d37ff5\"]\n        },\n        {\n          \"dmxRange\": [206, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Lavender\",\n          \"colors\": [\"#a011d9\"]\n        },\n        {\n          \"dmxRange\": [208, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#a011d9\"]\n        },\n        {\n          \"dmxRange\": [210, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Lavender\",\n          \"colors\": [\"#780da3\"]\n        },\n        {\n          \"dmxRange\": [212, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Congo Blue\",\n          \"colors\": [\"#471aee\"]\n        },\n        {\n          \"dmxRange\": [214, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Purple\",\n          \"colors\": [\"#da10d0\"]\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mauve\",\n          \"colors\": [\"#f0346a\"]\n        },\n        {\n          \"dmxRange\": [218, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose Pink\",\n          \"colors\": [\"#f35b86\"]\n        },\n        {\n          \"dmxRange\": [220, 221],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Follies Pink\",\n          \"colors\": [\"#f46c93\"]\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Pink\",\n          \"colors\": [\"#f2548c\"]\n        },\n        {\n          \"dmxRange\": [224, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Middle Rose\",\n          \"colors\": [\"#f577a4\"]\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Medium Pink\",\n          \"colors\": [\"#f8a6c3\"]\n        },\n        {\n          \"dmxRange\": [228, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#fcd4e2\"]\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark Pink\",\n          \"colors\": [\"#f2548c\"]\n        },\n        {\n          \"dmxRange\": [232, 233],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flesh Pink\",\n          \"colors\": [\"#fdd3d3\"]\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Green-Magenta Point\": {\n      \"name\": \"Green-Magenta Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Full minus green\"\n        },\n        {\n          \"dmxRange\": [21, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [120, 145],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [146, 244],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Full plus green\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Candle\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"TV\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Police\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Paparazzi\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Scroll\"\n        },\n        {\n          \"dmxRange\": [90, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"FX Param 1\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"FX Param 2\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"FX Param 3\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"FX Param 4\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"FX Param 5\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"CIE x\": {\n      \"fineChannelAliases\": [\"CIE x fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…0.85\"\n      }\n    },\n    \"CIE y\": {\n      \"fineChannelAliases\": [\"CIE y fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…0.85\"\n      }\n    },\n    \"CIE x2\": {\n      \"fineChannelAliases\": [\"CIE x2 fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…0.85\"\n      }\n    },\n    \"CIE y2\": {\n      \"fineChannelAliases\": [\"CIE y2 fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…0.85\"\n      }\n    },\n    \"Crossfade\": {\n      \"fineChannelAliases\": [\"Crossfade fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"CCT … Color Mix\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P1 DIMMING & CCT\",\n      \"shortName\": \"P1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"P2 HSI + CCT, Gel 8bit\",\n      \"shortName\": \"P2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Gel\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P3 CCT, RGB 8bit\",\n      \"shortName\": \"P3\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P4 FX 8bit\",\n      \"shortName\": \"P4\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Effect\",\n        \"Color Temperature\",\n        \"FX Param 1\",\n        \"FX Param 2\",\n        \"FX Param 3\",\n        \"FX Param 4\",\n        \"FX Param 5\"\n      ]\n    },\n    {\n      \"name\": \"P5 CIE xy 8bit\",\n      \"shortName\": \"P5\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CIE x\",\n        \"CIE y\"\n      ]\n    },\n    {\n      \"name\": \"P6 CCT 16bit\",\n      \"shortName\": \"P6\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"P7 HSI & CCT, Gel 16bit\",\n      \"shortName\": \"P7\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Gel\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P8 CCT, RGB 16bit\",\n      \"shortName\": \"P8\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P9 FX 16bit\",\n      \"shortName\": \"P9\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Effect\",\n        \"Color Temperature\",\n        \"FX Param 1\",\n        \"FX Param 2\",\n        \"FX Param 3\",\n        \"FX Param 4\",\n        \"FX Param 5\"\n      ]\n    },\n    {\n      \"name\": \"P10 CIE xy 16bit\",\n      \"shortName\": \"P10\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CIE x\",\n        \"CIE y\"\n      ]\n    },\n    {\n      \"name\": \"P11 CCT 8bit\",\n      \"shortName\": \"P11\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"P12 CCT 16bit\",\n      \"shortName\": \"P12\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point\"\n      ]\n    },\n    {\n      \"name\": \"P13 Gel 8bit\",\n      \"shortName\": \"P13\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Gel\"\n      ]\n    },\n    {\n      \"name\": \"P14 Gel 16bit\",\n      \"shortName\": \"P14\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Gel\"\n      ]\n    },\n    {\n      \"name\": \"P15 HSI & CCT 8bit\",\n      \"shortName\": \"P15\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P16 HSI & CCT 16bit\",\n      \"shortName\": \"P16\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P17 RGB & CCT 8bit\",\n      \"shortName\": \"P17\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P18 RGB & CCT 16bit\",\n      \"shortName\": \"P18\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    },\n    {\n      \"name\": \"P19 CIE xy 8bit\",\n      \"shortName\": \"P19\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CIE x\",\n        \"CIE y\"\n      ]\n    },\n    {\n      \"name\": \"P20 CIE xy 16bit\",\n      \"shortName\": \"P20\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CIE x\",\n        \"CIE x fine\",\n        \"CIE y\",\n        \"CIE y fine\"\n      ]\n    },\n    {\n      \"name\": \"P21 FX 8bit\",\n      \"shortName\": \"P21\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Effect\",\n        \"Color Temperature\",\n        \"FX Param 1\",\n        \"FX Param 2\",\n        \"FX Param 3\",\n        \"FX Param 4\",\n        \"FX Param 5\"\n      ]\n    },\n    {\n      \"name\": \"P22 FX 16bit\",\n      \"shortName\": \"P22\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Effect\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"FX Param 1\",\n        \"FX Param 2\",\n        \"FX Param 3\",\n        \"FX Param 4\",\n        \"FX Param 5\"\n      ]\n    },\n    {\n      \"name\": \"P23 xfade CCT & HSI 8bit\",\n      \"shortName\": \"P23\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Color Temperature 2\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"P24 xfade CCT & HSI 16bit\",\n      \"shortName\": \"P24\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"P25 xfade CCT & RBG 8bit\",\n      \"shortName\": \"P25\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Color Temperature 2\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P26 xfade CCT & RBG 16bit\",\n      \"shortName\": \"P26\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    },\n    {\n      \"name\": \"P27 xfade CIE xy1 & CIE xy2 8bit\",\n      \"shortName\": \"P27\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CIE x\",\n        \"CIE y\",\n        \"Crossfade\",\n        \"CIE x2\",\n        \"CIE y2\"\n      ]\n    },\n    {\n      \"name\": \"P28 xfade CIE xy1 & CIE xy2 16bit\",\n      \"shortName\": \"P28\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CIE x\",\n        \"CIE x fine\",\n        \"CIE y\",\n        \"CIE y fine\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"CIE x2\",\n        \"CIE x2 fine\",\n        \"CIE y2\",\n        \"CIE y2 fine\"\n      ]\n    },\n    {\n      \"name\": \"P29 xfade CCT & TDRGB 8bit\",\n      \"shortName\": \"P29\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Tungsten\",\n        \"Daylight\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P30 xfade CCT & TDRGB 16bit\",\n      \"shortName\": \"P30\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Green-Magenta Point\",\n        \"Crossfade\",\n        \"Crossfade fine\",\n        \"Tungsten\",\n        \"Tungsten fine\",\n        \"Daylight\",\n        \"Daylight fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/kino-flo/celeb-led-201-dmx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Celeb LED 201 DMX\",\n  \"shortName\": \"Celeb 201\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2022-05-07\",\n    \"lastModifyDate\": \"2022-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.kinoflotest2.com/PDF/News/Operational%20Manual%20for%20the%20web/3100084%20Rev%20A%20Celeb%20201%20LED%20DMX%2007-01-2015.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.kinoflotest2.com/Products%20Button/LED/Celeb%20200%20DMX/Celeb200_DMX.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=TK2RRkvcjL8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [610, 360, 130],\n    \"weight\": 6.8,\n    \"power\": 100,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 22],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2700K\",\n          \"colorTemperatureEnd\": \"3030K\"\n        },\n        {\n          \"dmxRange\": [23, 32],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"3045K\",\n          \"colorTemperatureEnd\": \"3171K\"\n        },\n        {\n          \"dmxRange\": [33, 114],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"3185K\",\n          \"colorTemperatureEnd\": \"4400K\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"4415K\",\n          \"colorTemperatureEnd\": \"4471K\"\n        },\n        {\n          \"dmxRange\": [120, 181],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"4485K\",\n          \"colorTemperatureEnd\": \"5400K\"\n        },\n        {\n          \"dmxRange\": [182, 186],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"5415K\",\n          \"colorTemperatureEnd\": \"5471K\"\n        },\n        {\n          \"dmxRange\": [187, 249],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"5485K\",\n          \"colorTemperatureEnd\": \"6415K\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"6430K\",\n          \"colorTemperatureEnd\": \"6500K\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"DIMMING + CCT\",\n      \"shortName\": \"DIM+CCT\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/kino-flo/celeb-led-250-dmx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\",\n  \"name\": \"Celeb 250-DMX\",\n  \"redirectTo\": \"kino-flo/celeb-250-led-dmx\",\n  \"reason\": \"FixtureRenamed\"\n}\n"
  },
  {
    "path": "fixtures/kino-flo/celeb-led-450-dmx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\",\n  \"name\": \"Celeb 450-DMX\",\n  \"redirectTo\": \"kino-flo/celeb-450-led-dmx\",\n  \"reason\": \"FixtureRenamed\"\n}\n"
  },
  {
    "path": "fixtures/lalucenatz/18leds-par-light.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"18LEDs Par Light\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anomes\"],\n    \"createDate\": \"2019-09-21\",\n    \"lastModifyDate\": \"2019-09-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images-na.ssl-images-amazon.com/images/I/B1vDZm6YD0S.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.amazon.com/dp/B00WU5OM5M/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=tXqQy4PfIeA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [175, 175, 99],\n    \"weight\": 0.8,\n    \"power\": 21,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18× 1W LEDs (6× red, 6× green, 6× blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Master\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"RGB\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"helpWanted\": \"Which color can be selected at which DMX values?\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"helpWanted\": \"Is this really fast…slow or slow…fast?\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"helpWanted\": \"What does this channel do? Which modes can be selected at which DMX values?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Master\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Master\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"RGB\",\n        \"Strobe\",\n        \"Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lalucenatz/dj-lights.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DJ Lights\",\n  \"categories\": [\"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2020-04-17\",\n    \"lastModifyDate\": \"2020-04-17\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.amazon.com/dp/B011QEVO44\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=jYfDDvw0aEU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [188, 196, 229],\n    \"weight\": 1.3,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"30W LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red + Orange Dimmer\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green + Purple Dimmer\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue + White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Green + Yellow Dimmer\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"The manual states fast…slow, which direction is correct? At which DMX values is the light constantly on or off?\"\n      }\n    },\n    \"Light Always On\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"What does this channel do?\"\n      }\n    },\n    \"Sound Mode\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound mode\",\n        \"helpWanted\": \"At which DMX values is sound mode deactivated? Are there different effects at different DMX values?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red + Orange Dimmer\",\n        \"Green + Purple Dimmer\",\n        \"Blue + White\",\n        \"Green + Yellow Dimmer\",\n        \"Shutter / Strobe\",\n        \"Light Always On\",\n        \"Sound Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/laserworld/cs-1000rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"CS-1000RGB\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Jo\"],\n    \"createDate\": \"2018-07-26\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.laserworld.com/en/download-file-49-CS_1000RGB_D_E_F_MKIII_web.html\"\n    ],\n    \"productPage\": [\n      \"https://www.laserworld.com/en/laserworld-cs/laserworld-cs-1000rgb.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=u9m3_SWDQeU\"\n    ]\n  },\n  \"helpWanted\": \"Most information about the capabilities of the channels are missing.\",\n  \"physical\": {\n    \"dimensions\": [220, 155, 145],\n    \"weight\": 3.15,\n    \"power\": 60,\n    \"bulb\": {\n      \"type\": \"650nm / 532nm / 445nm RGB Laser diodes\"\n    }\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"capability\": {\n        \"type\": \"Maintenance\"\n      }\n    },\n    \"Pattern\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Circular Movement\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Y Rotation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"X Rotation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Horizontal Movement\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"BeamPosition\",\n        \"horizontalAngleStart\": \"0deg\",\n        \"horizontalAngleEnd\": \"40deg\"\n      }\n    },\n    \"Vertical Movement\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"BeamPosition\",\n        \"verticalAngleStart\": \"0deg\",\n        \"verticalAngleEnd\": \"40deg\"\n      }\n    },\n    \"Manual Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Pattern Buildup\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Dot Effect with Strobe\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Color\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Pattern\",\n        \"Circular Movement\",\n        \"Y Rotation\",\n        \"X Rotation\",\n        \"Horizontal Movement\",\n        \"Vertical Movement\",\n        \"Manual Zoom\",\n        \"Pattern Buildup\",\n        \"Dot Effect with Strobe\",\n        \"Color\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/laserworld/ds-1000rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DS-1000RGB\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"finnTE\"],\n    \"createDate\": \"2019-01-08\",\n    \"lastModifyDate\": \"2019-01-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.laserworld.com/en/download-file-51-Laserworld_Diode_Series_web.html\"\n    ],\n    \"productPage\": [\n      \"https://www.laserworld.com/en/laserworld-ds/laserworld-ds-1000rgb.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=IbVylAJv3_0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 110, 140],\n    \"weight\": 2.8,\n    \"power\": 40,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Mode Select\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Laser Off\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode (beam patterns)\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode (graphics)\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"DMX Mode\"\n        }\n      ]\n    },\n    \"Pattern Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Graphics patterns\"\n        },\n        {\n          \"dmxRange\": [88, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"Beam patterns\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Laser Off\"\n        }\n      ]\n    },\n    \"Strobe Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Horizontal Movement\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngle\": \"center\"\n        },\n        {\n          \"dmxRange\": [1, 167],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"left\",\n          \"horizontalAngleEnd\": \"right\"\n        },\n        {\n          \"dmxRange\": [168, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement rightwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [189, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement leftwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement rightwards/leftwards alternating\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngle\": \"center\"\n        }\n      ]\n    },\n    \"Vertical Movement\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"BeamPosition\",\n          \"verticalAngle\": \"center\"\n        },\n        {\n          \"dmxRange\": [1, 167],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"top\",\n          \"verticalAngleEnd\": \"bottom\"\n        },\n        {\n          \"dmxRange\": [168, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement downwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [189, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement upwards\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement downwards/upwards alternating\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"BeamPosition\",\n          \"verticalAngle\": \"center\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 167],\n          \"type\": \"Zoom\",\n          \"angleStart\": \"narrow\",\n          \"angleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [168, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Increasing angle\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [189, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Decreasing angle\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Alternate decreasing/increasing angle\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Opposite zoom of X- and Y-axis\"\n        }\n      ]\n    },\n    \"Rotation Y-axis\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 150],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Correct angle?\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotation X-axis\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 150],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Correct angle?\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotation Z-axis\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 180],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Correct angle?\"\n        },\n        {\n          \"dmxRange\": [181, 217],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [218, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Blanking\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 70],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [71, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dot visibility\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [140, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dashed Lines\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Point selection\"\n        }\n      ]\n    },\n    \"Wave Movement\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave positioning\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave movement\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave movement\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Color Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [120, 138],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [139, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Multi-color\"\n        },\n        {\n          \"dmxRange\": [165, 248],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [249, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Changing multi-color\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Multi-color without red\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Mode Select\",\n        \"Pattern Selection\",\n        \"Strobe Effect\",\n        \"Horizontal Movement\",\n        \"Vertical Movement\",\n        \"Zoom\",\n        \"Rotation Y-axis\",\n        \"Rotation X-axis\",\n        \"Rotation Z-axis\",\n        \"Blanking\",\n        \"Wave Movement\",\n        \"Color Selection\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/laserworld/el-400rgb-mk2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"EL-400RGB MK2\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anon\", \"wagskydive\", \"Luke Nelson\"],\n    \"createDate\": \"2024-10-10\",\n    \"lastModifyDate\": \"2025-10-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.laserworld.com/en/download-file-1780-EL_400RGB_MK2_web.html\"\n    ],\n    \"productPage\": [\n      \"https://www.laserworld.com/en/laserworld-el/laserworld-el-400rgb\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=GKitAO4Y21o\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [255, 245, 100],\n    \"weight\": 3.1,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic mode\"\n        },\n        {\n          \"dmxRange\": [150, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static pattern\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic pattern\"\n        }\n      ]\n    },\n    \"Pattern Selection\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Pattern Selection\"\n      }\n    },\n    \"Horizontal Angle\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngle\": \"center\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"left\",\n          \"horizontalAngleEnd\": \"right\",\n          \"helpWanted\": \"Are the horizontal angle start and end values correct?\"\n        }\n      ]\n    },\n    \"Vertical Angle\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"BeamPosition\",\n          \"verticalAngle\": \"center\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"bottom\",\n          \"verticalAngleEnd\": \"top\",\n          \"helpWanted\": \"Are the vertical angle start and end values correct?\"\n        }\n      ]\n    },\n    \"Scanning Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\",\n        \"helpWanted\": \"Are the scanning speed start and end values correct?\"\n      }\n    },\n    \"Dynamic Pattern Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\",\n        \"helpWanted\": \"Are the dynamic pattern speed start and end values correct?\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\",\n        \"helpWanted\": \"Are the zoom start and end values correct?\"\n      }\n    },\n    \"Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Macros\",\n          \"comment\": \"Multi Color\",\n          \"helpWanted\": \"Does this cycle all possible colours? Is this a colorFade or colorJump?\"\n        },\n        {\n          \"dmxRange\": [2, 3],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [6, 7],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [16, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"helpWanted\": \"Why are there repeated capabilities for the same colours?\"\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [28, 33],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [34, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [40, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [46, 51],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [52, 57],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [58, 67],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [68, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [78, 87],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [88, 97],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [98, 107],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [108, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [138, 147],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [148, 157],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [158, 167],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [168, 177],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [178, 187],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [188, 197],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [198, 203],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [204, 209],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [210, 215],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [216, 221],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [222, 227],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [228, 233],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [234, 239],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [240, 241],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [242, 243],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [244, 245],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [246, 247],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [248, 249],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [250, 251],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [252, 253],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Color Segment\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Color Segment\",\n        \"helpWanted\": \"What does 'Color Segment' mean and is there a better fitting capability type?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Pattern Selection\",\n        \"Horizontal Angle\",\n        \"Vertical Angle\",\n        \"Scanning Speed\",\n        \"Dynamic Pattern Speed\",\n        \"Zoom\",\n        \"Color\",\n        \"Color Segment\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/laserworld/shownet.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ShowNET\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"elixxx\", \"Felix Edelmann\"],\n    \"createDate\": \"2020-02-16\",\n    \"lastModifyDate\": \"2020-02-16\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2020-02-16\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.1)\"\n    }\n  },\n  \"comment\": \"LAN interface to be used as DMX triggered playback system for laser show.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.laserworld.com/en/download-file-1243-ShowNET_extern_2020_web.html\"\n    ],\n    \"productPage\": [\n      \"https://www.laserworld.com/en/laser-software/showeditor-set.html\"\n    ]\n  },\n  \"physical\": {\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Patterns\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 1\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 2\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 3\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 4\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 5\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 6\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 7\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 8\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 9\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 10\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 11\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 12\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 13\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 14\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 15\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 16\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 17\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 18\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 19\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 20\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 21\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 22\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 23\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 24\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 25\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 26\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 27\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 28\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 29\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 30\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 31\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 32\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 33\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 34\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 35\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 36\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 37\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 38\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 39\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 40\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 41\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 42\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 43\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 44\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 45\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 46\"\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 47\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 48\"\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 49\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 50\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 51\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 52\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 53\"\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 54\"\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 55\"\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 56\"\n        },\n        {\n          \"dmxRange\": [57, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 57\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 58\"\n        },\n        {\n          \"dmxRange\": [59, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 59\"\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 60\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 61\"\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 62\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 63\"\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 64\"\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 65\"\n        },\n        {\n          \"dmxRange\": [66, 66],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 66\"\n        },\n        {\n          \"dmxRange\": [67, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 67\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 68\"\n        },\n        {\n          \"dmxRange\": [69, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 69\"\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 70\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 71\"\n        },\n        {\n          \"dmxRange\": [72, 72],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 72\"\n        },\n        {\n          \"dmxRange\": [73, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 73\"\n        },\n        {\n          \"dmxRange\": [74, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 74\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 75\"\n        },\n        {\n          \"dmxRange\": [76, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 76\"\n        },\n        {\n          \"dmxRange\": [77, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 77\"\n        },\n        {\n          \"dmxRange\": [78, 78],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 78\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 79\"\n        },\n        {\n          \"dmxRange\": [80, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 80\"\n        },\n        {\n          \"dmxRange\": [81, 81],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 81\"\n        },\n        {\n          \"dmxRange\": [82, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 82\"\n        },\n        {\n          \"dmxRange\": [83, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 83\"\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 84\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 85\"\n        },\n        {\n          \"dmxRange\": [86, 86],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 86\"\n        },\n        {\n          \"dmxRange\": [87, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 87\"\n        },\n        {\n          \"dmxRange\": [88, 88],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 88\"\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 89\"\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 90\"\n        },\n        {\n          \"dmxRange\": [91, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 91\"\n        },\n        {\n          \"dmxRange\": [92, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 92\"\n        },\n        {\n          \"dmxRange\": [93, 93],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 93\"\n        },\n        {\n          \"dmxRange\": [94, 94],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 94\"\n        },\n        {\n          \"dmxRange\": [95, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 95\"\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 96\"\n        },\n        {\n          \"dmxRange\": [97, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 97\"\n        },\n        {\n          \"dmxRange\": [98, 98],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 98\"\n        },\n        {\n          \"dmxRange\": [99, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 99\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 100\"\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 101\"\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 102\"\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 103\"\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 104\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 105\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 106\"\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 107\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 108\"\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 109\"\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 110\"\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 111\"\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 112\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 113\"\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 114\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 115\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 116\"\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 117\"\n        },\n        {\n          \"dmxRange\": [118, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 118\"\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 119\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 120\"\n        },\n        {\n          \"dmxRange\": [121, 121],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 121\"\n        },\n        {\n          \"dmxRange\": [122, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 122\"\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 123\"\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 124\"\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 125\"\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 126\"\n        },\n        {\n          \"dmxRange\": [127, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 127\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 128\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 129\"\n        },\n        {\n          \"dmxRange\": [130, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 130\"\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 131\"\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 132\"\n        },\n        {\n          \"dmxRange\": [133, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 133\"\n        },\n        {\n          \"dmxRange\": [134, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 134\"\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 135\"\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 136\"\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 137\"\n        },\n        {\n          \"dmxRange\": [138, 138],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 138\"\n        },\n        {\n          \"dmxRange\": [139, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 139\"\n        },\n        {\n          \"dmxRange\": [140, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 140\"\n        },\n        {\n          \"dmxRange\": [141, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 141\"\n        },\n        {\n          \"dmxRange\": [142, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 142\"\n        },\n        {\n          \"dmxRange\": [143, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 143\"\n        },\n        {\n          \"dmxRange\": [144, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 144\"\n        },\n        {\n          \"dmxRange\": [145, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 145\"\n        },\n        {\n          \"dmxRange\": [146, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 146\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 147\"\n        },\n        {\n          \"dmxRange\": [148, 148],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 148\"\n        },\n        {\n          \"dmxRange\": [149, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 149\"\n        },\n        {\n          \"dmxRange\": [150, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 150\"\n        },\n        {\n          \"dmxRange\": [151, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 151\"\n        },\n        {\n          \"dmxRange\": [152, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 152\"\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 153\"\n        },\n        {\n          \"dmxRange\": [154, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 154\"\n        },\n        {\n          \"dmxRange\": [155, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 155\"\n        },\n        {\n          \"dmxRange\": [156, 156],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 156\"\n        },\n        {\n          \"dmxRange\": [157, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 157\"\n        },\n        {\n          \"dmxRange\": [158, 158],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 158\"\n        },\n        {\n          \"dmxRange\": [159, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 159\"\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 160\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 161\"\n        },\n        {\n          \"dmxRange\": [162, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 162\"\n        },\n        {\n          \"dmxRange\": [163, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 163\"\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 164\"\n        },\n        {\n          \"dmxRange\": [165, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 165\"\n        },\n        {\n          \"dmxRange\": [166, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 166\"\n        },\n        {\n          \"dmxRange\": [167, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 167\"\n        },\n        {\n          \"dmxRange\": [168, 168],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 168\"\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 169\"\n        },\n        {\n          \"dmxRange\": [170, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 170\"\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 171\"\n        },\n        {\n          \"dmxRange\": [172, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 172\"\n        },\n        {\n          \"dmxRange\": [173, 173],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 173\"\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 174\"\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 175\"\n        },\n        {\n          \"dmxRange\": [176, 176],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 176\"\n        },\n        {\n          \"dmxRange\": [177, 177],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 177\"\n        },\n        {\n          \"dmxRange\": [178, 178],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 178\"\n        },\n        {\n          \"dmxRange\": [179, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 179\"\n        },\n        {\n          \"dmxRange\": [180, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 180\"\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 181\"\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 182\"\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 183\"\n        },\n        {\n          \"dmxRange\": [184, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 184\"\n        },\n        {\n          \"dmxRange\": [185, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 185\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 186\"\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 187\"\n        },\n        {\n          \"dmxRange\": [188, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 188\"\n        },\n        {\n          \"dmxRange\": [189, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 189\"\n        },\n        {\n          \"dmxRange\": [190, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 190\"\n        },\n        {\n          \"dmxRange\": [191, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 191\"\n        },\n        {\n          \"dmxRange\": [192, 192],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 192\"\n        },\n        {\n          \"dmxRange\": [193, 193],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 193\"\n        },\n        {\n          \"dmxRange\": [194, 194],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 194\"\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 195\"\n        },\n        {\n          \"dmxRange\": [196, 196],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 196\"\n        },\n        {\n          \"dmxRange\": [197, 197],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 197\"\n        },\n        {\n          \"dmxRange\": [198, 198],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 198\"\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 199\"\n        },\n        {\n          \"dmxRange\": [200, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 200\"\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 201\"\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 202\"\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 203\"\n        },\n        {\n          \"dmxRange\": [204, 204],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 204\"\n        },\n        {\n          \"dmxRange\": [205, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 205\"\n        },\n        {\n          \"dmxRange\": [206, 206],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 206\"\n        },\n        {\n          \"dmxRange\": [207, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 207\"\n        },\n        {\n          \"dmxRange\": [208, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 208\"\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 209\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 210\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 211\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 212\"\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 213\"\n        },\n        {\n          \"dmxRange\": [214, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 214\"\n        },\n        {\n          \"dmxRange\": [215, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 215\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 216\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 217\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 218\"\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 219\"\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 220\"\n        },\n        {\n          \"dmxRange\": [221, 221],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 221\"\n        },\n        {\n          \"dmxRange\": [222, 222],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 222\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 223\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 224\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 225\"\n        },\n        {\n          \"dmxRange\": [226, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 226\"\n        },\n        {\n          \"dmxRange\": [227, 227],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 227\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 228\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 229\"\n        },\n        {\n          \"dmxRange\": [230, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 230\"\n        },\n        {\n          \"dmxRange\": [231, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 231\"\n        },\n        {\n          \"dmxRange\": [232, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 232\"\n        },\n        {\n          \"dmxRange\": [233, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 233\"\n        },\n        {\n          \"dmxRange\": [234, 234],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 234\"\n        },\n        {\n          \"dmxRange\": [235, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 235\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 236\"\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 237\"\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 238\"\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 239\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 240\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 241\"\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 242\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 243\"\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 244\"\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 245\"\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 246\"\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 247\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 248\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 249\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 250\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 251\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 252\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 253\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 254\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"ILDA 255\"\n        }\n      ]\n    },\n    \"Pattern Speed DJ\": {\n      \"name\": \"Pattern Speed\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"50Hz\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"100Hz\"\n        }\n      ]\n    },\n    \"Pattern Speed\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"100Hz\"\n      }\n    },\n    \"Size\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"BeamAngle\",\n          \"angleStart\": \"wide\",\n          \"angleEnd\": \"closed\",\n          \"comment\": \"width and height\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"BeamAngle\",\n          \"angleStart\": \"wide\",\n          \"angleEnd\": \"closed\",\n          \"comment\": \"width\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"BeamAngle\",\n          \"angleStart\": \"wide\",\n          \"angleEnd\": \"closed\",\n          \"comment\": \"height\"\n        }\n      ]\n    },\n    \"Horizontal Size\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"BeamAngle\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"closed\"\n      }\n    },\n    \"Vertical Size\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"BeamAngle\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"closed\"\n      }\n    },\n    \"Automatic Size\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"changing width and height\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"changing width\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"changing height\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Rotation DJ\": {\n      \"name\": \"Rotation\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 192],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"-180deg\",\n          \"angleEnd\": \"180deg\",\n          \"helpWanted\": \"Are the angles correct?\"\n        },\n        {\n          \"dmxRange\": [193, 224],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotation\": {\n      \"fineChannelAliases\": [\"Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"-180deg\",\n        \"angleEnd\": \"180deg\",\n        \"helpWanted\": \"Are the angles correct?\"\n      }\n    },\n    \"Horizontal Position\": {\n      \"fineChannelAliases\": [\"Horizontal Position fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"BeamPosition\",\n        \"horizontalAngleStart\": \"left\",\n        \"horizontalAngleEnd\": \"right\"\n      }\n    },\n    \"Vertical Position\": {\n      \"fineChannelAliases\": [\"Vertical Position fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"BeamPosition\",\n        \"verticalAngleStart\": \"top\",\n        \"verticalAngleEnd\": \"bottom\"\n      }\n    },\n    \"Inversion\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Invert X axis\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Invert Y axis\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Invert X and Y axes\"\n        }\n      ]\n    },\n    \"Color Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Original colors\"\n        },\n        {\n          \"dmxRange\": [16, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single color (monochrome)\"\n        },\n        {\n          \"dmxRange\": [80, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Replace colors\"\n        },\n        {\n          \"dmxRange\": [144, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color change\"\n        }\n      ]\n    },\n    \"Color Effects Extended\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [128, 192],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic change of color fade effects\"\n        }\n      ]\n    },\n    \"Color Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Original colors\"\n        },\n        {\n          \"dmxRange\": [16, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [48, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [80, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [112, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [144, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Purple\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [176, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 50%\",\n          \"colors\": [\"#808080\"]\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Manual control\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual control\"\n        },\n        {\n          \"dmxRange\": [20, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto position X+Y\"\n        },\n        {\n          \"dmxRange\": [84, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto position X\"\n        },\n        {\n          \"dmxRange\": [148, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto position Y\"\n        },\n        {\n          \"dmxRange\": [212, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Demo mode\"\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-to-light\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Scan Speed DJ\": {\n      \"name\": \"Scan Speed\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 5,\n          \"parameterEnd\": 30,\n          \"comment\": \"Scan speed in kpps (thousands points per second):\",\n          \"helpWanted\": \"Is this actually 5…40kpps like in Professional Mode?\"\n        }\n      ]\n    },\n    \"Scan Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 5,\n          \"parameterEnd\": 40,\n          \"comment\": \"Scan speed in kpps (thousands points per second):\"\n        }\n      ]\n    },\n    \"Safety Zone\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety bottom\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety top\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety left\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety right\"\n        }\n      ]\n    },\n    \"Safety Zone Intensity DJ\": {\n      \"name\": \"Safety Zone Intensity\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No reduction\"\n        },\n        {\n          \"dmxRange\": [1, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reduction to 50% brightness\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reduction to blackout\"\n        }\n      ]\n    },\n    \"Safety Zone Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\",\n        \"comment\": \"Reduction\",\n        \"parameterStart\": \"0%\",\n        \"parameterEnd\": \"100%\"\n      }\n    },\n    \"Color Balancing Red\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"bright\",\n        \"brightnessEnd\": \"off\"\n      }\n    },\n    \"Color Balancing Green\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"bright\",\n        \"brightnessEnd\": \"off\"\n      }\n    },\n    \"Color Balancing Blue\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"bright\",\n        \"brightnessEnd\": \"off\"\n      }\n    },\n    \"Blanking\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 192],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Manual blanking\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Automatic blanking\",\n          \"parameterStart\": \"slow\",\n          \"parameterEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Blank Shift\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 192],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Manual blank shift\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Automatic blank shift\",\n          \"parameterStart\": \"slow\",\n          \"parameterEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Reserved 1\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 2\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 3\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 4\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 5\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 6\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 7\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 8\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 9\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 10\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved 11\": {\n      \"name\": \"Reserved\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"DJ\",\n      \"channels\": [\n        \"Intensity\",\n        \"Patterns\",\n        \"Pattern Speed DJ\",\n        \"Size\",\n        \"Automatic Size\",\n        \"Rotation DJ\",\n        \"Horizontal Position\",\n        \"Horizontal Position fine\",\n        \"Vertical Position\",\n        \"Vertical Position fine\",\n        \"Color Effects\",\n        \"Color Effects Extended\",\n        \"Strobe\",\n        \"Mode\",\n        \"Scan Speed DJ\",\n        \"Safety Zone\",\n        \"Safety Zone Intensity DJ\",\n        \"Blanking\",\n        \"Blank Shift\"\n      ]\n    },\n    {\n      \"name\": \"Professional\",\n      \"channels\": [\n        \"Intensity\",\n        \"Patterns\",\n        \"Pattern Speed\",\n        \"Horizontal Position\",\n        \"Horizontal Position fine\",\n        \"Vertical Position\",\n        \"Vertical Position fine\",\n        \"Rotation\",\n        \"Rotation fine\",\n        \"Horizontal Size\",\n        \"Vertical Size\",\n        \"Inversion\",\n        \"Color Selection\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Scan Speed\",\n        \"Safety Zone\",\n        \"Safety Zone Intensity\",\n        \"Color Balancing Red\",\n        \"Color Balancing Green\",\n        \"Color Balancing Blue\",\n        \"Reserved 1\",\n        \"Reserved 2\",\n        \"Reserved 3\",\n        \"Reserved 4\",\n        \"Reserved 5\",\n        \"Reserved 6\",\n        \"Reserved 7\",\n        \"Reserved 8\",\n        \"Reserved 9\",\n        \"Reserved 10\",\n        \"Reserved 11\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ledj/slimline-12q5-rgba.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Slimline 12Q5 RGBA\",\n  \"shortName\": \"LEDJ67B\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-03-14\",\n    \"lastModifyDate\": \"2019-03-14\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://prolight.co.uk/ftp-in/LEDJ67B_Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.prolight.co.uk/Catalogue/Products/Lighting/Battens/LEDJ67XX?selected=LEDJ67B&ou=%2fproduct%2fslimline-12q5-rgba-batten-black-housing\",\n      \"https://www.prolight.co.uk/Catalogue/Products/Lighting/Battens/LEDJ67XX?selected=LEDJ67C&ou=%2fproduct%2fslimline-12q5-rgba-batten-white-housing\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=q9vZgmnNnco\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [87, 1018, 63],\n    \"weight\": 2.2,\n    \"power\": 70,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 5W RGBA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 240],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"helpWanted\": \"Is the strobe speed controllable here (e.g. slow…fast)?\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color macro\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values? Or is this a color change effect?\"\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer / Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"Color Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ledj/slimline-12q5-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Slimline 12Q5 RGBW\",\n  \"shortName\": \"LEDJ67\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2019-03-14\",\n    \"lastModifyDate\": \"2019-03-14\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://prolight.co.uk/ftp-in/LEDJ67_Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.prolight.co.uk/Catalogue/Products/Lighting/Battens/LEDJ67XX?selected=LEDJ67&ou=%2fproduct%2fslimline-12q5-rgba-batten-black-housing\",\n      \"https://www.prolight.co.uk/Catalogue/Products/Lighting/Battens/LEDJ67XX?selected=LEDJ67A&ou=%2fproduct%2fslimline-12q5-rgba-batten-white-housing\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=q9vZgmnNnco\",\n      \"https://www.youtube.com/watch?v=Xvl8oeKIhH4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [87, 1018, 63],\n    \"weight\": 2.2,\n    \"power\": 70,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 5W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 240],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"helpWanted\": \"Is the strobe speed controllable here (e.g. slow…fast)?\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color macro\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values? Or is this a color change effect?\"\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer / Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Color Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lep-laser/diamond-pro-2-8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Diamond PRO 2.8\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dirk\"],\n    \"createDate\": \"2019-10-15\",\n    \"lastModifyDate\": \"2019-10-15\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2019-10-15\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.2)\"\n    }\n  },\n  \"links\": {\n    \"video\": [\n      \"https://www.youtube.com/watch?v=YHbKlJp-M9k\"\n    ]\n  },\n  \"helpWanted\": \"Can you provide a link to a manual?\",\n  \"physical\": {\n    \"dimensions\": [334, 125, 390],\n    \"weight\": 7.0,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Mode Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Laser off\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound mode, shutoff after 2 sec\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound mode (beam patterns)\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound mode (graphics)\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Mode\"\n        }\n      ]\n    },\n    \"Pattern Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 Line horizontal\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Lines horizontal stacked\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Lines horizontal side by side\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 Line vertical\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Lines vertical side by side\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Lines horizontal stacked\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Effect\",\n          \"effectName\": \"Swastika-like pattern\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sinus\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Sinus diagonally across each other\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cardiogram\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rectangle pulsed line\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Square\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Squares diagonally across each other\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Square big\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rectangle\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Triangle\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Maze Square\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Maze Triangle\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Effect\",\n          \"effectName\": \"Yin Yang\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Half Circle up\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big Circle\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Circles same center\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"5 Circles form a square\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"4-pointed Star\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"5-pointed Star\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pentagon\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Effect\",\n          \"effectName\": \"Octagon\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 thin Spikes\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 thick Spikes\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"5 thick Spikes\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Stars twinkling\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Diamond horizontal\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Diamonds vertical\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Heart\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 lines every 45 degrees\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 lightnings\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 Circles\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"5 Circles\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 Fishes\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"5 Lines horizontal diagonal\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 short lines horizontal\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 short lines vertical\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Effect\",\n          \"effectName\": \"7 Big points horizontal diagonal\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"7 Big points vertical diagonal\"\n        },\n        {\n          \"dmxRange\": [44, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big Letter S\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"7 Small circles vertical\"\n        },\n        {\n          \"dmxRange\": [46, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"5 thin spikes\"\n        },\n        {\n          \"dmxRange\": [47, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big circle with breaks\"\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big Square with breaks\"\n        },\n        {\n          \"dmxRange\": [49, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"6 lines every 60 degrees\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tumbler\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Medium Circle\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big Arrow Right\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big Square\"\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tongs\"\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hourglass\"\n        },\n        {\n          \"dmxRange\": [56, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Small circle 1…12 Hour CW\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 deranged arrows\"\n        },\n        {\n          \"dmxRange\": [69, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 arrows\"\n        },\n        {\n          \"dmxRange\": [70, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"Diagonal lines\"\n        },\n        {\n          \"dmxRange\": [74, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big circle with breaks\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 Groups of 4 Triangles\"\n        },\n        {\n          \"dmxRange\": [76, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big Letter V\"\n        },\n        {\n          \"dmxRange\": [77, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Big Letters XY\"\n        },\n        {\n          \"dmxRange\": [78, 78],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sinus\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Stars Twinkling\"\n        },\n        {\n          \"dmxRange\": [80, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"7 Triangles vertical\"\n        },\n        {\n          \"dmxRange\": [81, 81],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle with 8 arrows\"\n        },\n        {\n          \"dmxRange\": [82, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 Circles\"\n        },\n        {\n          \"dmxRange\": [83, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Welcome\"\n        },\n        {\n          \"dmxRange\": [90, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"Stars\"\n        },\n        {\n          \"dmxRange\": [93, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dancer\"\n        },\n        {\n          \"dmxRange\": [96, 98],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hearts colliding\"\n        },\n        {\n          \"dmxRange\": [99, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tumbler growing\"\n        },\n        {\n          \"dmxRange\": [101, 102],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle\"\n        },\n        {\n          \"dmxRange\": [103, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dotted Circle\"\n        },\n        {\n          \"dmxRange\": [105, 106],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dancing vertical line\"\n        },\n        {\n          \"dmxRange\": [107, 108],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dotted horizontal line up…down\"\n        },\n        {\n          \"dmxRange\": [109, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Circles dancing\"\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wobbly Sinus\"\n        },\n        {\n          \"dmxRange\": [117, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dotted Sinus up…down\"\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 dotted horizontal lines up…down\"\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 diagonals up…down\"\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Circles dancing\"\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"Effect\",\n          \"effectName\": \"Points Sinus up…down\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 horizontal lines revolving\"\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 dotted lines dancing\"\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 dancing dotted vertical lines\"\n        },\n        {\n          \"dmxRange\": [133, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 dancing vertical sinus\"\n        },\n        {\n          \"dmxRange\": [135, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Lines revolving\"\n        },\n        {\n          \"dmxRange\": [137, 255],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Can no pattern be selected in this DMX range?\"\n        }\n      ]\n    },\n    \"Strobe Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Horizontal Movement\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngle\": \"center\"\n        },\n        {\n          \"dmxRange\": [1, 42],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"center\",\n          \"horizontalAngleEnd\": \"right\"\n        },\n        {\n          \"dmxRange\": [43, 127],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"right\",\n          \"horizontalAngleEnd\": \"left\"\n        },\n        {\n          \"dmxRange\": [128, 167],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngleStart\": \"left\",\n          \"horizontalAngleEnd\": \"center\"\n        },\n        {\n          \"dmxRange\": [168, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement left…right alternating\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [189, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement right…left alternating\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [211, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement 5 Steps right…left alternating\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"BeamPosition\",\n          \"horizontalAngle\": \"center\"\n        }\n      ]\n    },\n    \"Vertical Movement\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"BeamPosition\",\n          \"verticalAngle\": \"center\"\n        },\n        {\n          \"dmxRange\": [1, 42],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"center\",\n          \"verticalAngleEnd\": \"bottom\"\n        },\n        {\n          \"dmxRange\": [43, 127],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"bottom\",\n          \"verticalAngleEnd\": \"top\"\n        },\n        {\n          \"dmxRange\": [128, 167],\n          \"type\": \"BeamPosition\",\n          \"verticalAngleStart\": \"top\",\n          \"verticalAngleEnd\": \"center\"\n        },\n        {\n          \"dmxRange\": [168, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement bottom…top alternating\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [189, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement top…bottom alternating\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [211, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movement 5 Steps bottom…top alternating\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"BeamPosition\",\n          \"verticalAngle\": \"center\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 109],\n          \"type\": \"Zoom\",\n          \"angleStart\": \"narrow\",\n          \"angleEnd\": \"wide\"\n        },\n        {\n          \"dmxRange\": [110, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom in\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [155, 204],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom out\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Alternate zoom in/out\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Rotation Y-axis\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 150],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotation X-axis\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 150],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotation Z-axis\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 180],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [181, 217],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [218, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Blanking\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dots visible with Pattern\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dashed Lines\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dots instead of Pattern\"\n        }\n      ]\n    },\n    \"Wave Movement\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wave overlay to Pattern\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"Is this capability correct?\"\n        }\n      ]\n    },\n    \"Color Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [30, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [36, 138],\n          \"type\": \"Generic\",\n          \"helpWanted\": \"Which colors can be selected in this DMX range?\"\n        },\n        {\n          \"dmxRange\": [139, 164],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Multi-color\"\n        },\n        {\n          \"dmxRange\": [165, 174],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [175, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Changing multi-color\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Mode Select\",\n        \"Pattern Selection\",\n        \"Strobe Effect\",\n        \"Horizontal Movement\",\n        \"Vertical Movement\",\n        \"Zoom\",\n        \"Rotation Y-axis\",\n        \"Rotation X-axis\",\n        \"Rotation Z-axis\",\n        \"Blanking\",\n        \"Wave Movement\",\n        \"Color Selection\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/light-sky/aurora.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Aurora\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"LIGHT SKY\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-09-21\",\n    \"lastModifyDate\": \"2019-09-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://en.lightsky.com.cn/wp-content/uploads/2021/06/AURORA-UserManual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://en.lightsky.com.cn/product/aurora/\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 39,\n    \"softwareVersion\": \"1.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [401, 646, 300],\n    \"weight\": 58,\n    \"power\": 620,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Osram Sirius HRI 471W SN\",\n      \"colorTemperature\": 6300,\n      \"lumens\": 695400\n    },\n    \"lens\": {\n      \"name\": \"φ160 Optical lens with high precision\",\n      \"degreesMinMax\": [3, 42]\n    }\n  },\n  \"wheels\": {\n    \"Effect Disk\": {\n      \"slots\": [\n        {\n          \"type\": \"AnimationGoboStart\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"40%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"30%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"20%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"10%\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark red\",\n          \"colors\": [\"#fe0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff450c\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aquamarine\",\n          \"colors\": [\"#01fdfd\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark green\",\n          \"colors\": [\"#006401\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#01ff01\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#bfbff3\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#febeca\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#fef100\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#e5007f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00a1e9\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO2\",\n          \"colors\": [\"#e79d6c\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO1\",\n          \"colors\": [\"#f2be9b\"],\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark blue\",\n          \"colors\": [\"#1f1586\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"250deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Standard mode\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Max. speed mode\"\n        },\n        {\n          \"dmxRange\": [2, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LCD display On\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LCD display Off\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"High CRI\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard CRI\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fans mode: Auto\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fans mode: High\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp On\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt reset\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color reset\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo reset\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer/Shutter reset\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom/focus/frost/prism wheels reset\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Effect wheel reset\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total reset\"\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp Off\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [27, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [46, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [55, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [73, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [82, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [101, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [110, 118],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [119, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [135, 138],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [139, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [148, 152],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [153, 157],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [158, 161],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [162, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [167, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [172, 176],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [177, 180],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [186, 189],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 13,\n          \"slotNumberEnd\": 14\n        },\n        {\n          \"dmxRange\": [190, 215],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [218, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color selection\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto random color\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Effect Disk Positioning\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 127],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\",\n          \"comment\": \"Effect Disk insertion\",\n          \"helpWanted\": \"Or can you select the rotation angle of the Effect Disk here?\"\n        },\n        {\n          \"dmxRange\": [128, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ramping from open to full position\"\n        },\n        {\n          \"dmxRange\": [171, 213],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ramping from open to half position\"\n        },\n        {\n          \"dmxRange\": [214, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ramping from half position to full position\"\n        }\n      ]\n    },\n    \"Effect Disk Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Effect Disk\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Effect Disk\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Effect Disk\",\n          \"speed\": \"stop\",\n          \"comment\": \"No rotation\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Effect Disk\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [4, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [34, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [40, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [46, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [52, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [58, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [64, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [70, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [76, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [82, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [202, 222],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [223, 228],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [229, 249],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto random gobo selection\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [17, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [29, 40],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [41, 52],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [53, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [65, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [77, 88],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [89, 100],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [101, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [113, 124],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [125, 136],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [137, 148],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [149, 160],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [161, 172],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [173, 184],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [185, 196],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [197, 208],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [209, 220],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 249],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto random gobo selection\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\",\n          \"helpWanted\": \"Are these the correct angles?\"\n        },\n        {\n          \"dmxRange\": [128, 187],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [188, 195],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [196, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism 1 Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism 1 Indexing/Rotation\": \"Prism 1 Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [4, 15],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet 12° circular, indexing\",\n          \"switchChannels\": {\n            \"Prism 1 Indexing/Rotation\": \"Prism 1 Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 27],\n          \"type\": \"Prism\",\n          \"comment\": \"4-facet 12° circular, indexing\",\n          \"switchChannels\": {\n            \"Prism 1 Indexing/Rotation\": \"Prism 1 Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 39],\n          \"type\": \"Prism\",\n          \"comment\": \"6-facet linear, indexing\",\n          \"switchChannels\": {\n            \"Prism 1 Indexing/Rotation\": \"Prism 1 Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 51],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet 12° circular, rotating\",\n          \"switchChannels\": {\n            \"Prism 1 Indexing/Rotation\": \"Prism 1 Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 63],\n          \"type\": \"Prism\",\n          \"comment\": \"4-facet 12° circular, rotating\",\n          \"switchChannels\": {\n            \"Prism 1 Indexing/Rotation\": \"Prism 1 Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 75],\n          \"type\": \"Prism\",\n          \"comment\": \"6-facet linear, rotating\",\n          \"switchChannels\": {\n            \"Prism 1 Indexing/Rotation\": \"Prism 1 Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [76, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism 1 Indexing/Rotation\": \"Prism 1 Rotation\"\n          }\n        }\n      ]\n    },\n    \"Prism 1 Indexing\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\",\n        \"helpWanted\": \"Are these the correct angles?\"\n      }\n    },\n    \"Prism 1 Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism 2 Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism 2 Indexing/Rotation\": \"Prism 2 Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [4, 15],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet 18° circular, indexing\",\n          \"switchChannels\": {\n            \"Prism 2 Indexing/Rotation\": \"Prism 2 Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 27],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet 18° circular, rotating\",\n          \"switchChannels\": {\n            \"Prism 2 Indexing/Rotation\": \"Prism 2 Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism 2 Indexing/Rotation\": \"Prism 2 Rotation\"\n          }\n        }\n      ]\n    },\n    \"Prism 2 Indexing\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\",\n        \"helpWanted\": \"Are these the correct angles?\"\n      }\n    },\n    \"Prism 2 Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism Macro Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [4, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing prism macro 1\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing prism macro 2\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing prism macro 3\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [37, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing prism macro 4\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing prism macro 5\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [59, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing prism macro 6\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing prism macro 7\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 1\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [92, 102],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 2\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 113],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 3\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [114, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 4\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [125, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 5\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 6\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [147, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 7\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [158, 168],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 8\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [169, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 9\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation prism macro 10\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism Macro Indexing/Rotation\": \"Prism Macro Rotation\"\n          }\n        }\n      ]\n    },\n    \"Prism Macro Indexing\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\",\n        \"helpWanted\": \"Are these the correct angles?\"\n      }\n    },\n    \"Prism Macro Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 50],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"0%\",\n          \"frostIntensityEnd\": \"100%\",\n          \"comment\": \"light frost\"\n        },\n        {\n          \"dmxRange\": [51, 53],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"100%\",\n          \"comment\": \"light frost\"\n        },\n        {\n          \"dmxRange\": [54, 63],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse closing\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"comment\": \"light frost\"\n        },\n        {\n          \"dmxRange\": [64, 73],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse opening\",\n          \"speedStart\": \"10Hz\",\n          \"speedEnd\": \"0.1Hz\",\n          \"comment\": \"light frost\"\n        },\n        {\n          \"dmxRange\": [74, 83],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramping\",\n          \"speedStart\": \"10Hz\",\n          \"speedEnd\": \"0.1Hz\",\n          \"comment\": \"light frost\"\n        },\n        {\n          \"dmxRange\": [84, 86],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [87, 136],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"0%\",\n          \"frostIntensityEnd\": \"100%\",\n          \"comment\": \"medium frost\"\n        },\n        {\n          \"dmxRange\": [137, 139],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"100%\",\n          \"comment\": \"medium frost\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse closing\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"comment\": \"medium frost\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse opening\",\n          \"speedStart\": \"10Hz\",\n          \"speedEnd\": \"0.1Hz\",\n          \"comment\": \"medium frost\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramping\",\n          \"speedStart\": \"10Hz\",\n          \"speedEnd\": \"0.1Hz\",\n          \"comment\": \"medium frost\"\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [173, 222],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"0%\",\n          \"frostIntensityEnd\": \"100%\",\n          \"comment\": \"medium frost, 100% light frost\"\n        },\n        {\n          \"dmxRange\": [223, 225],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"100%\",\n          \"comment\": \"medium frost, 100% light frost\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse closing\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"comment\": \"light+medium frost\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse opening\",\n          \"speedStart\": \"10Hz\",\n          \"speedEnd\": \"0.1Hz\",\n          \"comment\": \"light+medium frost\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramping\",\n          \"speedStart\": \"10Hz\",\n          \"speedEnd\": \"0.1Hz\",\n          \"comment\": \"light+medium frost\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Focus 2\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Autofocus\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Autofocus off\"\n        },\n        {\n          \"dmxRange\": [16, 55],\n          \"type\": \"Focus\",\n          \"distance\": \"10m\"\n        },\n        {\n          \"dmxRange\": [56, 95],\n          \"type\": \"Focus\",\n          \"distance\": \"15m\"\n        },\n        {\n          \"dmxRange\": [96, 135],\n          \"type\": \"Focus\",\n          \"distance\": \"20m\"\n        },\n        {\n          \"dmxRange\": [136, 175],\n          \"type\": \"Focus\",\n          \"distance\": \"30m\"\n        },\n        {\n          \"dmxRange\": [176, 215],\n          \"type\": \"Focus\",\n          \"distance\": \"40m\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Focus\",\n          \"distance\": \"50m\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"opening pulses\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"closing pulses\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"full lamp power\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"33-channel\",\n      \"shortName\": \"33ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Control\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Effect Disk Positioning\",\n        \"Effect Disk Rotation\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism 1 Selection\",\n        \"Prism 1 Indexing/Rotation\",\n        \"Prism 2 Selection\",\n        \"Prism 2 Indexing/Rotation\",\n        \"Prism Macro Selection\",\n        \"Prism Macro Indexing/Rotation\",\n        \"Frost\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Focus 2\",\n        \"Autofocus\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        null\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/light4me/led-par-18x3w-uv.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR 18x3W UV\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2024-11-16\",\n    \"lastModifyDate\": \"2024-11-16\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://light4me.pl/en/product/light4me-led-par-18x3w-uv/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [175, 175, 100],\n    \"weight\": 0.8,\n    \"power\": 55,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18x3W UV LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"UV 1\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"UV 2\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"UV 3\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Is this slow…fast or fast…slow?\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macros\",\n          \"helpWanted\": \"Which macros can be selected at which DMX values?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"UV 1\",\n        \"UV 2\",\n        \"UV 3\",\n        \"Macro Speed\",\n        \"Strobe\",\n        \"Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/cls-nano-cob.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"CLS Nano COB\",\n  \"categories\": [\"Stand\", \"Color Changer\", \"Dimmer\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"prtr\", \"Luke Nelson\"],\n    \"createDate\": \"2023-10-15\",\n    \"lastModifyDate\": \"2023-10-15\"\n  },\n  \"comment\": \"4 RGB COB Spots, 30W each\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.musicstore.com/INTERSHOP/web/WFS/MusicStore-MusicStoreShop-Site/de_DE/ms-ch/CHF/ViewProductAttachment-ResolveManualURL?File=DE_LIG0015657-000.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.musicstore.com/en_OE/EUR/lightmaXX-CLS-Nano-COB/art-LIG0015657-000\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_Jfp0JCAOns\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [720, 200, 110],\n    \"weight\": 5.7,\n    \"power\": 130,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"All\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 99],\n          \"type\": \"Intensity\",\n          \"brightness\": \"100%\",\n          \"comment\": \"Full ON\"\n        },\n        {\n          \"dmxRange\": [100, 129],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"erratic\"\n        },\n        {\n          \"dmxRange\": [130, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [160, 189],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [190, 219],\n          \"type\": \"Effect\",\n          \"soundControlled\": true,\n          \"effectName\": \"Music Mode 1\"\n        },\n        {\n          \"dmxRange\": [220, 249],\n          \"type\": \"Effect\",\n          \"soundControlled\": true,\n          \"effectName\": \"Music Mode 2\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"soundControlled\": true,\n          \"effectName\": \"Music Mode 3\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red All\",\n        \"Green All\",\n        \"Blue All\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red All\",\n        \"Green All\",\n        \"Blue All\",\n        \"Color Presets\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"16ch individual Spot RGB + effects\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Color Presets\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/dj-scan-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DJ Scan LED\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Thilo Billerbeck\"],\n    \"createDate\": \"2018-02-06\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\"https://www.musicstore.de/INTERSHOP/web/WFS/MusicStore-MusicStoreShop-Site/de_DE/-/EUR/ViewProductAttachment-ResolveManualURL?File=DE_LIG0007774-000.pdf\"],\n    \"video\": [\"https://www.youtube.com/watch?v=eNepec8pVrg\"]\n  },\n  \"physical\": {\n    \"dimensions\": [465, 150, 150],\n    \"weight\": 3,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"25W LED\"\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [14, 27],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [28, 41],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [42, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [56, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8000ff\"],\n          \"comment\": \"Purple\"\n        },\n        {\n          \"dmxRange\": [70, 83],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0040ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [84, 97],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff80\"],\n          \"comment\": \"Light Green\"\n        },\n        {\n          \"dmxRange\": [98, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8000\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [27, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [36, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [45, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [54, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [63, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [72, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [81, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [90, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [99, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [108, 116],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [117, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [126, 134],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [135, 143],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [144, 152],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [153, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [162, 170],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [171, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [180, 188],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [189, 197],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [198, 206],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [207, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 10,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [20, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Strobe effect 1\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [138, 201],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Strobe effect 2\"\n        },\n        {\n          \"dmxRange\": [202, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Function/Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"C/G Motor reset\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All Motor reset\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 1\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 2\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 3\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 4\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 5\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 6\"\n        },\n        {\n          \"dmxRange\": [220, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 7\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 8\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Normal\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Function/Program\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/easy-wash-quad-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Easy Wash Quad LED\",\n  \"shortName\": \"LightmaXXEasyWashQuad\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Paul Maier\", \"Felix Edelmann\"],\n    \"createDate\": \"2018-11-02\",\n    \"lastModifyDate\": \"2018-11-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://forum.malighting.com/attachment/475-lightmaxx-easy-wash-quad-led-7x10w-rgbw-pdf/\"\n    ],\n    \"productPage\": [\n      \"https://www.musicstore.com/en_RS/EUR/lightmaXX-Easy-Wash-Quad-Moving-Head-LED/art-LIG0009642-000\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=7gJw-aAvHPg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [225, 270, 225],\n    \"weight\": 4.2,\n    \"power\": 90,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7x 10W RGBW LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Shutter / Dimmer\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 134],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [135, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"40Hz\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White (RGB)\"\n        },\n        {\n          \"dmxRange\": [22, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [35, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [50, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [64, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [78, 91],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aad9ff\"],\n          \"comment\": \"Light blue\"\n        },\n        {\n          \"dmxRange\": [92, 105],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a21a19\"],\n          \"comment\": \"Crimson\"\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [120, 133],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#982aff\"],\n          \"comment\": \"Purple\"\n        },\n        {\n          \"dmxRange\": [134, 147],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaa00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [148, 161],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a3ffab\"],\n          \"comment\": \"Light green\"\n        },\n        {\n          \"dmxRange\": [162, 175],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [176, 189],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd0d0\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [190, 203],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a0ab76\"],\n          \"comment\": \"Buff\"\n        },\n        {\n          \"dmxRange\": [204, 217],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffaa\"],\n          \"comment\": \"White (RGW)\"\n        },\n        {\n          \"dmxRange\": [218, 231],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7000b1\"],\n          \"comment\": \"Dark Purple\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        }\n      ]\n    },\n    \"Color Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Or is it fast…slow?\"\n      }\n    },\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 1\"\n        },\n        {\n          \"dmxRange\": [23, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 2\"\n        },\n        {\n          \"dmxRange\": [38, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 3\"\n        },\n        {\n          \"dmxRange\": [54, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 4\"\n        },\n        {\n          \"dmxRange\": [68, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 5\"\n        },\n        {\n          \"dmxRange\": [83, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 6\"\n        },\n        {\n          \"dmxRange\": [98, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 7\"\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 8\"\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [143, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [158, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [173, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [188, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [203, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [218, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-Channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Shutter / Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Pan/Tilt Speed\"\n      ]\n    },\n    {\n      \"name\": \"13-Channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Color Speed\",\n        \"Effects\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/led-blinder-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Blinder 4\",\n  \"categories\": [\"Blinder\"],\n  \"meta\": {\n    \"authors\": [\"Leon Dietrich\"],\n    \"createDate\": \"2026-02-02\",\n    \"lastModifyDate\": \"2026-02-02\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.musicstore.com/en_OT/EUR/lightmaXX-LED-Blinder-4/art-LIG0016527-000\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=QpehbQvLv7c&pp=ygUXbGlnaHRtYXh4IGxlZCBibGluZGVyIDQ%3D\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [195, 315, 315],\n    \"weight\": 4.5,\n    \"power\": 210,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1\", \"3\"],\n        [\"2\", \"4\"]\n      ]\n    ]\n  },\n  \"templateChannels\": {\n    \"Intensity $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"on-off-iterate\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [71, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"fade-iterate\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"fade rotated\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"on-off rotated\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"No function\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Effect\",\n        \"No function\",\n        \"Intensity 1\",\n        \"Intensity 2\",\n        \"Intensity 3\",\n        \"Intensity 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/led-nano-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Nano PAR\",\n  \"shortName\": \"LED Nano PAR\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Peter Eisemann\", \"Flo Edelmann\"],\n    \"createDate\": \"2021-10-30\",\n    \"lastModifyDate\": \"2021-10-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.musicstore.de/INTERSHOP/web/WFS/MusicStore-MusicStoreShop-Site/en_US/-/EUR/ViewProductAttachment-ResolveManualURL?File=EN_LIG0013274-000.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.musicstore.com/en_US/USD/lightmaXX-LED-NANO-PAR-black-12-1W-LED-RGBW/art-LIG0013274-000\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=UakWorWVxpE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [150, 140, 115],\n    \"weight\": 0.4,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 1W LED\"\n    },\n    \"lens\": {\n      \"name\": \"15mm Edison EDOL 25\",\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Static Colors\",\n          \"helpWanted\": \"What does channel 2 control exactly when not in static colors mode?\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Flash\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        }\n      ]\n    },\n    \"Color Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Chase\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green\",\n          \"colors\": [\"#00ff00\", \"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + White\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + White\",\n          \"colors\": [\"#00ff00\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + White\",\n          \"colors\": [\"#0000ff\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + White\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue + White\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + White\",\n          \"colors\": [\"#00ff00\", \"#0000ff\", \"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\"]\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Program\",\n        \"Color Program\",\n        \"Program Speed\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/led-par-56.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Par 56\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\"],\n    \"createDate\": \"2021-08-05\",\n    \"lastModifyDate\": \"2021-08-05\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.scherloc.com/_media/notice-par56led-10mm.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.musicstore.de/en_US/USD/lightmaXX-LED-Par-56-RGB-Short-Polish-10mm-LEDs/art-LIG0002658-000\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [220, 210, 220],\n    \"weight\": 1.4,\n    \"power\": 22,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"108x LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 189],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [190, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/led-par-64-cob-100w-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR 64 COB 100W RGB\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Mindful\", \"Flo Edelmann\"],\n    \"createDate\": \"2026-01-28\",\n    \"lastModifyDate\": \"2026-03-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://ls-systems.be/matos/lumiere/spot/LIGHTMAXX%20-%20PAR64%20COB%20RGB%20100W.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.musicstore.com/en_OE/EUR/lightmaXX-LED-PAR-64-COB-100W-RGB-polish/art-LIG0010192-000\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [240, 195, 390],\n    \"weight\": 2.6,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED Array Cluster\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Sound / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control (7 Colors)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Sound / Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/platinum-mini-tri-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Platinum Mini TRI-PAR\",\n  \"shortName\": \"MiniTri\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-02-24\",\n    \"lastModifyDate\": \"2018-09-22\"\n  },\n  \"comment\": \"Platinum Line Mini TRI-PAR 7x3 Watt\",\n  \"links\": {\n    \"manual\": [\"https://www.musicstore.de/INTERSHOP/web/WFS/MusicStore-MusicStoreShop-Site/de_DE/-/EUR/ViewProductAttachment-ResolveManualURL?File=DE_LIG0008746-000.pdf\"],\n    \"video\": [\"https://www.youtube.com/watch?v=P5xIg3SfnnY\"]\n  },\n  \"physical\": {\n    \"dimensions\": [170, 170, 160],\n    \"weight\": 2.0,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25.0, 25.0]\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity\": {\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#add8e6\"],\n          \"comment\": \"Light blue\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#800080\"],\n          \"comment\": \"Purple\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb6c1\"],\n          \"comment\": \"Light pink\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ca1f7b\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e75480\"],\n          \"comment\": \"Dark pink\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7f00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#facc00\"],\n          \"comment\": \"Light orange\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#90ee90\"],\n          \"comment\": \"Light green\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7fffd4\"],\n          \"comment\": \"Aquamarine\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [85, 169],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [170, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"highlightValue\": 200,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\"Intensity\", \"Red\", \"Green\", \"Blue\", \"Macro\", \"Strobe\"]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/vector-haze-1-0.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Vector Haze 1.0\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2022-11-17\",\n    \"lastModifyDate\": \"2022-11-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.musicstore.com/INTERSHOP/web/WFS/MusicStore-MusicStoreShop-Site/en_US/ms-us/USD/ViewProductAttachment-ResolveManualURL?File=EN_LIG0015638-000.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.musicstore.com/en_US/USD/lightmaXX-Vector-Haze-1-0/art-LIG0015638-000\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=MAu3bCSxxIo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [495, 235, 405],\n    \"weight\": 16.7,\n    \"power\": 1100,\n    \"DMXconnector\": \"3-pin and 5-pin\"\n  },\n  \"availableChannels\": {\n    \"Fan Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Haze Output\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Haze\",\n        \"fogOutputStart\": \"weak\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Fan Speed\",\n        \"Haze Output\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/vector-pixel-bar-18x-15w-rgbwa.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Vector Pixel BAR 18x 15W RGBWA\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Stephan Klein\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-03-29\",\n    \"lastModifyDate\": \"2020-03-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.musicstore.de/INTERSHOP/web/WFS/MusicStore-MusicStoreShop-Site/de_DE/-/EUR/ViewProductAttachment-ResolveManualURL?File=DE_LIG0016266-000.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.musicstore.com/en_US/USD/lightmaXX-Vector-Pixel-BAR-18x-15W-RGBWA/art-LIG0016266-000\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1130, 150, 210],\n    \"weight\": 8,\n    \"power\": 180,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18× 15W RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [18, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 17],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [18, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change\",\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Running Effects\"\n          }\n        },\n        {\n          \"dmxRange\": [23, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Colorful running jump change\",\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Color Running Effect Direction\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Colorful running gradual change\",\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Color Running Effect Direction\"\n          }\n        },\n        {\n          \"dmxRange\": [33, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color\",\n          \"helpWanted\": \"What does this capability do?\",\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 42],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [43, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effects 1…50\",\n          \"helpWanted\": \"Which running effect is active at which DMX values?\",\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Unused\"\n          }\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound to light\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Running Effects / Color Running Effect Direction\": \"Unused\"\n          }\n        }\n      ]\n    },\n    \"Running Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 1\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 2\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 3\"\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 4\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 5\"\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 6\"\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 7\"\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 8\"\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 9\"\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 10\"\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 11\"\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 12\"\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 13\"\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 14\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 15\"\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 16\"\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 17\"\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 18\"\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 19\"\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 20\"\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 21\"\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 22\"\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 23\"\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 24\"\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 25\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 26\"\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 27\"\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 28\"\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 29\"\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 30\"\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 31\"\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 32\"\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 33\"\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 34\"\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 35\"\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 36\"\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 37\"\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 38\"\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 39\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 40\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 41\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 42\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 43\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 44\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 45\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 46\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 47\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 48\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 49\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Running effect 50\",\n          \"helpWanted\": \"According to the manual, this capability starts at 251. If it does, how are the DMX ranges of the other capabilities?\"\n        }\n      ]\n    },\n    \"Color Running Effect Direction\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"left running\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"right running\"\n        }\n      ]\n    },\n    \"Unused\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Function Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"RGBWA Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Function\",\n        \"Running Effects / Color Running Effect Direction\",\n        \"Function Speed\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\"\n      ]\n    },\n    {\n      \"name\": \"28-channel\",\n      \"shortName\": \"28ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Function\",\n        \"Running Effects / Color Running Effect Direction\",\n        \"Function Speed\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"RGBWA Dimmer $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"90-channel\",\n      \"shortName\": \"90ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"100-channel\",\n      \"shortName\": \"100ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Function\",\n        \"Running Effects / Color Running Effect Direction\",\n        \"Function Speed\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/vega-bat-1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Vega BAT-1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"lukah\", \"Hasky\", \"Ryan Goodwin\"],\n    \"createDate\": \"2023-07-07\",\n    \"lastModifyDate\": \"2023-07-07\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2023-07-07\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.7)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/2405631/Lightmaxx-Vega-Bat-1.html?page=17\"\n    ],\n    \"productPage\": [\n      \"https://www.musicstore.com/en_OT/EUR/lightmaXX-Vega-BAT-1-6x-10W-RGBWA-UV-Battery/art-LIG0016452-000\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Th-FB_z6dj0\"\n    ]\n  },\n  \"physical\": {\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Program Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 64],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual Color Adjustment\"\n        },\n        {\n          \"dmxRange\": [65, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color Macros\",\n          \"helpWanted\": \"Which color macros are available and at what DMX values?\"\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [151, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Program Mode\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lightmaxx/vega-zoom-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Vega Zoom Wash\",\n  \"shortName\": \"VegaZoomWash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-02-24\",\n    \"lastModifyDate\": \"2018-09-22\"\n  },\n  \"links\": {\n    \"manual\": [\"https://www.musicstore.de/INTERSHOP/web/WFS/MusicStore-MusicStoreShop-Site/de_DE/-/EUR/ViewProductAttachment-ResolveManualURL?File=DE_LIG0013617-000.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=tJM8ScD-bLE\",\n      \"https://www.youtube.com/watch?v=RGQ9Nuvg3Xk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [260, 280, 340],\n    \"weight\": 4.5,\n    \"power\": 95,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [6, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"190deg\"\n      }\n    },\n    \"Pan / Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 245],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"cold\",\n        \"colorTemperatureEnd\": \"warm\"\n      }\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#8080ff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ff80\"],\n          \"comment\": \"Green + White\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8080\"],\n          \"comment\": \"Red + White\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff80\"],\n          \"comment\": \"Red + Green + White\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#80ffff\"],\n          \"comment\": \"Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Macro off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"6deg\",\n        \"angleEnd\": \"46deg\"\n      }\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 1\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 2\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 3\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 4\"\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 5\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 6\"\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 7\"\n        },\n        {\n          \"dmxRange\": [161, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Internal Program 8\"\n        },\n        {\n          \"dmxRange\": [181, 200],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [201, 225],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Motor reset\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan / Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Temperature\",\n        \"Color Macro\",\n        \"Macro Speed\",\n        \"Program\",\n        \"Zoom\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lite-tek/beam-230.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Beam 230\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"josequioss\"],\n    \"createDate\": \"2019-10-02\",\n    \"lastModifyDate\": \"2019-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://lite-tek.com.mx/manuales/BEAM-230.pdf\"\n    ],\n    \"productPage\": [\n      \"https://lite-tek.com.mx/producto/beam-230/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=hXLsF72Pnk4\",\n      \"https://www.youtube.com/watch?v=dMQJ2XyHWTE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [350, 505, 320],\n    \"weight\": 20.1,\n    \"power\": 320,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"YODN 7R\",\n      \"colorTemperature\": 8000,\n      \"lumens\": 8500\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#e50015\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffa300\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aquamarine\",\n          \"colors\": [\"#83d1ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00993f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light green\",\n          \"colors\": [\"#00ff01\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#878ddd\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#fec0cb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#fff001\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#e50081\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00dce5\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO 260\",\n          \"colors\": [\"#ff9416\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO 190\",\n          \"colors\": [\"#fea94e\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB 8000\",\n          \"colors\": [\"#e5eaff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0c1397\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"direction\": \"CW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [9, 12],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [13, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [18, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [26, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [35, 38],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [39, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [43, 46],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [47, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 68],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [69, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [73, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [77, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [82, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10.5\n        },\n        {\n          \"dmxRange\": [86, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [90, 93],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11.5\n        },\n        {\n          \"dmxRange\": [94, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [99, 102],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12.5\n        },\n        {\n          \"dmxRange\": [103, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [107, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13.5\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14.5\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15.5\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [72, 113],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [114, 117],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [118, 159],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [160, 166],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [167, 172],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [173, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [180, 185],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [186, 191],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 198],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [199, 204],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [205, 211],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [212, 217],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [218, 223],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 230],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [231, 236],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [237, 243],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 16,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 17,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Color and Prism macros\",\n        \"helpWanted\": \"At which DMX values can which macros be selected?\"\n      }\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [12, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [25, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [38, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [51, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [63, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 62],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [64, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Lamp\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 62],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\"\n        },\n        {\n          \"dmxRange\": [64, 177],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [178, 178],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [179, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Color Wheel\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Gobo Wheel\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Color Macros\",\n        \"Frost\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Macros\",\n        \"Reset\",\n        \"Lamp\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litecraft/washx-21.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"WashX.21\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"birk\", \"Flo Edelmann\"],\n    \"createDate\": \"2021-08-20\",\n    \"lastModifyDate\": \"2021-08-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/426053_washx21_de_uk.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/litecraft_washx.21.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [493, 320, 99],\n    \"weight\": 8.8,\n    \"power\": 184,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"21× RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Extended Strobe\": {\n      \"name\": \"Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [31, 100],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [101, 130],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [131, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"],\n          \"comment\": \"Red … Yellow\"\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"Yellow … Green\"\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"],\n          \"comment\": \"Green … Cyan\"\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Cyan … Blue\"\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"],\n          \"comment\": \"Blue … Magenta\"\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"],\n          \"comment\": \"Magenta … Red\"\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"],\n          \"comment\": \"Red … White\"\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"White … Blue\"\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Full White\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"Which colors can be selected in these capabilities?\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 29],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"dmxRange\": [30, 53],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [54, 77],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [78, 101],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [102, 125],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [126, 149],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [150, 173],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7000K\"\n        },\n        {\n          \"dmxRange\": [174, 197],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [198, 221],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"9000K\"\n        },\n        {\n          \"dmxRange\": [222, 245],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"10000K\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Auto Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [61, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [111, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [161, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5 (1-4)\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 52],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Dimmer mode set on display\"\n        },\n        {\n          \"dmxRange\": [53, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Mode off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Mode fast\"\n        },\n        {\n          \"dmxRange\": [153, 202],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Mode medium\"\n        },\n        {\n          \"dmxRange\": [203, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer Mode slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Extended Strobe\",\n        \"Color Macro\",\n        \"Color Temperature\",\n        \"Auto Program\",\n        \"Program Speed\",\n        \"Dimmer Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litecraft/washx-432-sw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"WashX.432 sw\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Julian Vogel\"],\n    \"createDate\": \"2026-02-03\",\n    \"lastModifyDate\": \"2026-02-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://lmp.de/media/pdf/40/96/0b/A184886_washx-432-sw_manual_de_en.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/de/litecraft_washx.432_sw.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [370, 227, 113],\n    \"weight\": 3.5,\n    \"power\": 120,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"432x Multichip LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 204],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"3000K\",\n          \"colorTemperatureEnd\": \"6400K\"\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEDs 100%\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cold White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cold White\"\n      }\n    },\n    \"Warm White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel Macro + Dimmer\",\n      \"shortName\": \"MC+DIM\",\n      \"channels\": [\n        \"Color Temperature\",\n        \"Intensity\"\n      ]\n    },\n    {\n      \"name\": \"2-channel Cold White + Warm White\",\n      \"shortName\": \"CW+WW\",\n      \"channels\": [\n        \"Cold White\",\n        \"Warm White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/litemat-plus-1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LiteMat Plus 1\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/304/litemat-plus/10019/litemat-plus-1-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=uE4WXRj5IhE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [533, 292, 23],\n    \"weight\": 1.13,\n    \"power\": 50,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 2548\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/litemat-plus-2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LiteMat Plus 2\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/304/litemat-plus/10018/litemat-plus-2-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=uE4WXRj5IhE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [533, 533, 23],\n    \"weight\": 1.72,\n    \"power\": 100,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 5096\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/litemat-plus-2l.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LiteMat Plus 2L\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/304/litemat-plus/10020/litemat-plus-2l-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=uE4WXRj5IhE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1016, 292, 23],\n    \"weight\": 1.72,\n    \"power\": 100,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 5096\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/litemat-plus-3.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LiteMat Plus 3\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/304/litemat-plus/10021/litemat-plus-3-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=uE4WXRj5IhE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [775, 533, 23],\n    \"weight\": 2.18,\n    \"power\": 150,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 7644\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/litemat-plus-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LiteMat Plus 4\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/304/litemat-plus/10017/litemat-plus-4-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=uE4WXRj5IhE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1016, 533, 23],\n    \"weight\": 2.81,\n    \"power\": 200,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 10192\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/litemat-plus-8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LiteMat Plus 8\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/304/litemat-plus/3015/litemat-plus-8-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=TsezicAneA4\",\n      \"https://www.youtube.com/watch?v=uE4WXRj5IhE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1016, 1016, 23],\n    \"weight\": 4.72,\n    \"power\": 400,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 21880\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/litetile-plus-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LiteTile Plus 4\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/301/litetile/10008/litetile-plus-4-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litetile/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=-pmiFjAFt_U\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1182, 610, 14],\n    \"weight\": 2,\n    \"power\": 200,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 10192\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/litetile-plus-8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LiteTile Plus 8\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/301/litetile/10010/litetile-plus-8-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litetile/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=-pmiFjAFt_U\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [2337, 610, 19],\n    \"weight\": 3.5,\n    \"power\": 400,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 20384\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6200K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/s2-litemat-1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"S2 LiteMat 1\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-16\",\n    \"lastModifyDate\": \"2021-01-16\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/300/litemat-s2/10000/s2-litemat-1-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=MIG3IwVRmw8\",\n      \"https://www.youtube.com/watch?v=T8otm9VL_gc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [533, 292, 23],\n    \"weight\": 1.1,\n    \"power\": 50,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 2735\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/s2-litemat-2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"S2 LiteMat 2\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-16\",\n    \"lastModifyDate\": \"2021-01-16\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/300/litemat-s2/10002/s2-litemat-2-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=T8otm9VL_gc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [533, 533, 23],\n    \"weight\": 1.6,\n    \"power\": 100,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 5470\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/s2-litemat-2l.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"S2 LiteMat 2L\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-16\",\n    \"lastModifyDate\": \"2021-01-16\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/300/litemat-s2/9998/s2-litemat-2l-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=T8otm9VL_gc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1016, 292, 23],\n    \"weight\": 1.6,\n    \"power\": 100,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 5470\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/s2-litemat-3.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"S2 LiteMat 3\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/300/litemat-s2/9999/s2-litemat-3-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=T8otm9VL_gc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [775, 533, 23],\n    \"weight\": 2.1,\n    \"power\": 150,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 8205\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/litegear/s2-litemat-4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"S2 LiteMat 4\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2021-01-17\",\n    \"lastModifyDate\": \"2021-01-17\"\n  },\n  \"comment\": \"DMX controllable via separate LiteGear control device.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.litegear.com/download/300/litemat-s2/10001/s2-litemat-4-data-sheet.pdf\",\n      \"https://www.litegear.com/download/340/litedimmer-plus-duo/3042/litedimmer-plus-dc200-ac400-user-guide-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.litegear.com/litemat-3-2/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=T8otm9VL_gc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1016, 533, 23],\n    \"weight\": 2.6,\n    \"power\": 200,\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 10940\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer 2\": {\n      \"fineChannelAliases\": [\"Dimmer 2 fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"fineChannelAliases\": [\"Color Temperature fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    },\n    \"Color Temperature 2\": {\n      \"fineChannelAliases\": [\"Color Temperature 2 fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2600K\",\n        \"colorTemperatureEnd\": \"6000K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Single 8bit\",\n      \"shortName\": \"1x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit\",\n      \"shortName\": \"1x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\"\n      ]\n    },\n    {\n      \"name\": \"Double 8bit\",\n      \"shortName\": \"2x8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\",\n        \"Dimmer 2\",\n        \"Color Temperature 2\"\n      ]\n    },\n    {\n      \"name\": \"Double 16bit\",\n      \"shortName\": \"2x16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Temperature\",\n        \"Color Temperature fine\",\n        \"Dimmer 2\",\n        \"Dimmer 2 fine\",\n        \"Color Temperature 2\",\n        \"Color Temperature 2 fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lixada/mini-beam-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\",\n  \"name\": \"Mini Beam RGBW\",\n  \"redirectTo\": \"stage-right/mini-beam-rgbw\",\n  \"reason\": \"SameAsDifferentBrand\"\n}\n"
  },
  {
    "path": "fixtures/lixada/mini-gobo-moving-head-light.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mini Gobo Moving Head Light\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Freasy\", \"edohard\", \"strbackatomas\"],\n    \"createDate\": \"2018-10-10\",\n    \"lastModifyDate\": \"2024-05-07\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-10-10\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.10.4)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://forums.pioneerdj.com/hc/en-us/community/posts/360000675466-Lixada-25W-DMX-512-Mini-Moving-Head-8-Colours-with-9-11-channels\"\n    ],\n    \"productPage\": [\n      \"https://www.lixada.com/p-l0686us.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VY0OZTM9W68\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [210, 260, 280],\n    \"weight\": 2.67,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"10W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [11, 11]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pale Blue\",\n          \"colors\": [\"#88dddd\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 8,\n          \"helpWanted\": \"Which Gobo can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 8,\n          \"helpWanted\": \"Which Gobo can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Pan/Tilt moving\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Color Wheel moving\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Gobo Wheel moving\"\n        },\n        {\n          \"dmxRange\": [120, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound active mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Dimmer Type\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard Dimmer\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage Dimmer\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV Dimmer\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural Dimmer\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatrical Dimmer\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tacitly approve Dimmer\",\n          \"helpWanted\": \"What does this mean?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Control\",\n        \"Dimmer Type\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Control\",\n        \"Dimmer Type\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lixada/mini-moving-head-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\",\n  \"name\": \"Mini Moving Head RGBW\",\n  \"redirectTo\": \"stage-right/stage-wash-7x10w-led-moving-head\",\n  \"reason\": \"SameAsDifferentBrand\"\n}\n"
  },
  {
    "path": "fixtures/look/cryofog.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Cryofog\",\n  \"categories\": [\"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"coffeeholic\"],\n    \"createDate\": \"2021-08-05\",\n    \"lastModifyDate\": \"2021-08-05\"\n  },\n  \"comment\": \"Low fog machine with CO2 cooling.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.looksolutions.com/uploads/pdf/bed_cryo_hp_1d.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.looksolutions.com/produkte/cryo_fog/2.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [510, 300, 670],\n    \"weight\": 33,\n    \"power\": 2300,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Fog Intensity\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Fog\",\n        \"fogOutputStart\": \"off\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Fan\": {\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"speedStart\": \"slow CW\",\n        \"speedEnd\": \"fast CW\"\n      }\n    },\n    \"Cooling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Cooling valve closed\"\n        },\n        {\n          \"dmxRange\": [1, 254],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Cooling valve open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Fog Intensity\",\n        \"Fan\",\n        \"Cooling\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/look/viper-nt.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Viper NT\",\n  \"categories\": [\"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-02-18\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.looksolutions.com/uploads/pdf/bed_vipernt_1d.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.looksolutions.com/produkte/viper_nt/2.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=uw4HNAFkKgQ\",\n      \"https://www.youtube.com/watch?v=QYufuVasJWc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [230, 240, 470],\n    \"weight\": 8.6,\n    \"power\": 1300,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Pump\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Fog\",\n        \"fogOutputStart\": \"off\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Heat\": {\n      \"capability\": {\n        \"type\": \"Maintenance\",\n        \"comment\": \"Heat\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Pump\",\n        \"Heat\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/actionpanel-dual-color.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Actionpanel Dual Color\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/actionpanel-dual-color\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [205, 205, 105],\n    \"weight\": 2,\n    \"power\": 60,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/actionpanel-full-color.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Actionpanel Full Color\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/actionpanel-full-color\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [205, 205, 105],\n    \"weight\": 2,\n    \"power\": 60,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"G/M Point 8bit\": {\n      \"name\": \"G/M Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"G/M Point 16bit\": {\n      \"name\": \"G/M Point\",\n      \"fineChannelAliases\": [\"G/M Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 500],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [501, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"G/M Point 8bit\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"HSI 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/superpanel-dual-color-60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Superpanel Dual Color 60\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/superpanel-color-60-dual-color\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [650, 340, 110],\n    \"weight\": 9,\n    \"power\": 400,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/superpanel-full-color-60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Superpanel Full Color 60\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/superpanelpro-30-full-color-hard\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [650, 340, 110],\n    \"weight\": 9,\n    \"power\": 400,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"G/M Point 8bit\": {\n      \"name\": \"G/M Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"G/M Point 16bit\": {\n      \"name\": \"G/M Point\",\n      \"fineChannelAliases\": [\"G/M Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 500],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [501, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"G/M Point 8bit\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"HSI 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/superpanelpro-dual-color-30.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SuperpanelPRO Dual Color 30\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/superpanelpro-30-dual-color-hard\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=7JACuyHTCr8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [350, 353, 117],\n    \"weight\": 4.9,\n    \"power\": 220,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/superpanelpro-full-color-30.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SuperpanelPRO Full Color 30\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/superpanelpro-30-full-color-hard\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [350, 353, 117],\n    \"weight\": 4.9,\n    \"power\": 220,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"G/M Point 8bit\": {\n      \"name\": \"G/M Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"G/M Point 16bit\": {\n      \"name\": \"G/M Point\",\n      \"fineChannelAliases\": [\"G/M Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 500],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [501, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"G/M Point 8bit\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"HSI 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/ultrapanel-dual-color-60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Ultrapanel Dual Color 60\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/ultrapanel-color-60-hard-dual-color\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [650, 340, 110],\n    \"weight\": 9,\n    \"power\": 400,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/ultrapanel-full-color-60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Ultrapanel Full Color 60\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/ultrapanel-color-60-hard-full-color\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [650, 340, 110],\n    \"weight\": 9,\n    \"power\": 400,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"G/M Point 8bit\": {\n      \"name\": \"G/M Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"G/M Point 16bit\": {\n      \"name\": \"G/M Point\",\n      \"fineChannelAliases\": [\"G/M Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 500],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [501, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"G/M Point 8bit\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"HSI 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/ultrapanelpro-dual-color-30.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"UltrapanelPRO Dual Color 30\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/ultrapanelpro-30-dual-color-hard\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=hMF79NyyIS4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [350, 353, 117],\n    \"weight\": 4.9,\n    \"power\": 220,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/lupo/ultrapanelpro-full-color-30.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"UltrapanelPRO Full Color 30\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2023-10-24\",\n    \"lastModifyDate\": \"2023-10-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.lupo.it/download-file?id=1UphgNNR7MiMnJ9WUS9wugAt1K3Ve_F-J\"\n    ],\n    \"productPage\": [\n      \"https://www.lupo.it/en/video/ultrapanelpro-30-full-color-hard\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [350, 353, 117],\n    \"weight\": 4.9,\n    \"power\": 220,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"CCT\": {\n      \"fineChannelAliases\": [\"CCT fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6500K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"G/M Point 8bit\": {\n      \"name\": \"G/M Point\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"G/M Point 16bit\": {\n      \"name\": \"G/M Point\",\n      \"fineChannelAliases\": [\"G/M Point 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 500],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [501, 65535],\n          \"type\": \"Generic\",\n          \"comment\": \"-100%…+100%\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"fineChannelAliases\": [\"Hue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…360°\"\n      }\n    },\n    \"Saturation\": {\n      \"fineChannelAliases\": [\"Saturation fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"0…100%\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Strobe 16bit\": {\n      \"name\": \"Strobe\",\n      \"fineChannelAliases\": [\"Strobe 16bit fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1300],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1301, 65535],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CCT 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"G/M Point 8bit\",\n        \"CCT\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"CCT 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"CCT + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Hue\",\n        \"Saturation\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"HSI 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\"\n      ]\n    },\n    {\n      \"name\": \"HSI + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Hue\",\n        \"Hue fine\",\n        \"Saturation\",\n        \"Saturation fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 8bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CCT\",\n        \"G/M Point 8bit\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGBW 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\"\n      ]\n    },\n    {\n      \"name\": \"RGBW + Strobe 16bit\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CCT\",\n        \"CCT fine\",\n        \"G/M Point 16bit\",\n        \"G/M Point 16bit fine\",\n        \"Strobe 16bit\",\n        \"Strobe 16bit fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/magicfx/psyco2jet.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PSYCO2JET\",\n  \"shortName\": \"MFXPSYCO2Jet\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"MAGIC FX B.V.\"],\n    \"createDate\": \"2018-08-20\",\n    \"lastModifyDate\": \"2018-08-21\"\n  },\n  \"comment\": \"The PSYCO2JET is a moving CO₂ Jet which blows CO₂ clouds in multiple directions or creates a waving CO₂ effect with its 180 degrees rotating nozzle.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.magicfx.eu/app/uploads/2020/01/MAGICFX_PSYCO2JET_MANUAL.pdf\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20230318035553/https://www.magicfx.eu/product/magicfx-psyco2jet/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=l9QZ8UaUbmg\",\n      \"https://www.youtube.com/watch?v=E4rW5SLIgoo\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 1,\n    \"softwareVersion\": \"16973824\"\n  },\n  \"physical\": {\n    \"dimensions\": [250, 165, 330],\n    \"weight\": 9,\n    \"power\": 35,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Safety\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"Device disabled\"\n        },\n        {\n          \"dmxRange\": [100, 155],\n          \"type\": \"Generic\",\n          \"comment\": \"Device enabled\"\n        },\n        {\n          \"dmxRange\": [156, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Device test mode (CO₂ output is disabled)\"\n        }\n      ]\n    },\n    \"Angle\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"-90deg\",\n        \"angleEnd\": \"90deg\"\n      }\n    },\n    \"Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Output\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 199],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Valve off\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Valve on\"\n        }\n      ]\n    },\n    \"Preset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single pulse straight up (0°)\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 pulses distributed over 180° (-45° +45°)\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 pulses distributed over 180° (-90°, 0°, +90°)\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 pulses distributed over 180° (-90°, -30°, +30°, +90°)\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"5 pulses distributed over 180° (-90°, -45°, 0°, +45°, +90°)\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random pulses over 180°\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulse at +45°, pulse at -45°, pulse at +45°, sweep from -45° back to +45°\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Three sweeps over 180° (-90° to -54°, -18° to +18° and +54° to +90°)\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulse at -90°, pulse at +90°, pulse at -60°, pulse at +60°, pulse at -30°, pulse at +30°, long pulse at 0°\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sweep over 180°\"\n        }\n      ]\n    },\n    \"Direction\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"Left to right\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Bounce, beginning from left\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Generic\",\n          \"comment\": \"Bounce, beginning from right\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Right to left\"\n        }\n      ]\n    },\n    \"Go\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [200, 249],\n          \"type\": \"Generic\",\n          \"comment\": \"Continuous mode\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Step in preset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Safety\",\n      \"channels\": [\n        \"Safety\"\n      ]\n    },\n    {\n      \"name\": \"Raw\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Angle\",\n        \"Speed\",\n        \"Output\"\n      ]\n    },\n    {\n      \"name\": \"Preset\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Preset\",\n        \"Speed\",\n        \"Direction\",\n        \"Go\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/magicfx/smokejet.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SMOKEJET\",\n  \"shortName\": \"SMOKEJET\",\n  \"categories\": [\"Smoke\", \"Color Changer\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"MAGIC FX B.V.\"],\n    \"createDate\": \"2018-09-06\",\n    \"lastModifyDate\": \"2018-09-06\"\n  },\n  \"comment\": \"Smoke machine with built-in power LED’s which blows coloured smoked on stages. Can also be mounted in trusses and blow smoke downwards and sideways.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.magicfx.eu/app/uploads/2020/01/MAGICFX_SMOKEJET_MANUAL.pdf\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20230318035556/https://www.magicfx.eu/product/magicfx-smokejet/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=amAVrtUQr4g\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [193, 380, 345],\n    \"weight\": 12.6,\n    \"power\": 1420,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Chase\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 5\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 6\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 7\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 8\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 9\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 10\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 11\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 12\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 13\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 14\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 15\"\n        }\n      ]\n    },\n    \"Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"comment\": \"0…255 steps per min\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"1Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"Chase\",\n        \"Chase Speed\",\n        \"Master Dimmer\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/magicfx/stage-flame.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stage Flame\",\n  \"shortName\": \"MFXStageFlame\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Alejo Cervera\"],\n    \"createDate\": \"2018-06-13\",\n    \"lastModifyDate\": \"2018-08-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.magicfx.eu/app/uploads/2020/01/MAGICFX_STAGE-FLAME_MANUAL.pdf\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20230318035553/https://www.magicfx.eu/product/magicfx-stage-flame/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=YLeYRexsTmc\",\n      \"https://www.youtube.com/watch?v=HvRzNTf07aY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [310, 210, 360],\n    \"weight\": 11.5,\n    \"power\": 100,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Safety\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety ON\"\n        },\n        {\n          \"dmxRange\": [140, 153],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety OFF\"\n        },\n        {\n          \"dmxRange\": [154, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Safety ON\"\n        }\n      ]\n    },\n    \"Flame\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"off\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"Flame Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Default\",\n      \"channels\": [\n        \"Safety\",\n        \"Flame\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/manufacturers.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/manufacturers.json\",\n  \"5star-systems\": {\n    \"name\": \"5Star Systems\"\n  },\n  \"abstract\": {\n    \"name\": \"Abstract\",\n    \"website\": \"https://www.abstract.co.uk/\"\n  },\n  \"acoustic-control\": {\n    \"name\": \"Acoustic Control\",\n    \"website\": \"https://kinson.pro/manufacturers/acoustic-control.html\"\n  },\n  \"adb\": {\n    \"name\": \"ADB\",\n    \"website\": \"https://www.adbstagelight.com\",\n    \"rdmId\": 16708\n  },\n  \"afx\": {\n    \"name\": \"AFX\",\n    \"website\": \"https://lotronic.net/gb/brand/15-afx\"\n  },\n  \"alien-pro\": {\n    \"name\": \"Alien Pro\",\n    \"website\": \"http://alienpro.com.mx/\"\n  },\n  \"american-dj\": {\n    \"name\": \"American DJ\",\n    \"website\": \"https://www.adj.com/\"\n  },\n  \"ape-labs\": {\n    \"name\": \"Ape Labs\",\n    \"website\": \"https://apelabs.com/\"\n  },\n  \"aputure\": {\n    \"name\": \"Aputure\",\n    \"website\": \"https://www.aputure.com\"\n  },\n  \"arri\": {\n    \"name\": \"ARRI\",\n    \"website\": \"https://www.arri.com/en\",\n    \"rdmId\": 8377\n  },\n  \"astera\": {\n    \"name\": \"Astera\",\n    \"website\": \"https://astera-led.com/\",\n    \"rdmId\": 16755\n  },\n  \"audibax\": {\n    \"name\": \"Audibax\"\n  },\n  \"ayra\": {\n    \"name\": \"Ayra\",\n    \"website\": \"https://www.bax-shop.co.uk/ayra\"\n  },\n  \"ayrton\": {\n    \"name\": \"Ayrton\",\n    \"website\": \"https://www.ayrton.eu/\"\n  },\n  \"beamz\": {\n    \"name\": \"BeamZ\",\n    \"comment\": \"Brand of the Tronios Group.\",\n    \"website\": \"https://www.tronios.com/lighting/filter/brand_beamz/\"\n  },\n  \"big-dipper\": {\n    \"name\": \"Big Dipper\",\n    \"website\": \"https://bigdipper-laser.com/\"\n  },\n  \"bitfocus\": {\n    \"name\": \"Bitfocus\",\n    \"website\": \"https://bitfocus.io/\"\n  },\n  \"blizzard\": {\n    \"name\": \"Blizzard\",\n    \"website\": \"https://www.blizzardpro.com/\"\n  },\n  \"boomtonedj\": {\n    \"name\": \"BoomToneDJ\",\n    \"website\": \"http://www.boomtonedj.com/\"\n  },\n  \"briteq\": {\n    \"name\": \"Briteq\",\n    \"website\": \"https://briteq-lighting.com/\",\n    \"rdmId\": 8482\n  },\n  \"cameo\": {\n    \"name\": \"cameo\",\n    \"website\": \"https://www.cameolight.com/\"\n  },\n  \"chauvet-dj\": {\n    \"name\": \"Chauvet DJ\",\n    \"website\": \"https://www.chauvetdj.com/\"\n  },\n  \"chauvet-professional\": {\n    \"name\": \"Chauvet Professional\",\n    \"website\": \"https://www.chauvetprofessional.com/\",\n    \"rdmId\": 8612\n  },\n  \"chroma-q\": {\n    \"name\": \"Chroma-Q\",\n    \"website\": \"https://chroma-q.com/\",\n    \"rdmId\": 21360\n  },\n  \"cinetec\": {\n    \"name\": \"Cinetec\",\n    \"website\": \"https://www.dimatec.net/cinetec.html\"\n  },\n  \"clay-paky\": {\n    \"name\": \"Clay Paky\",\n    \"website\": \"https://www.claypaky.it/en/\",\n    \"rdmId\": 17232\n  },\n  \"clf\": {\n    \"name\": \"CLF\",\n    \"website\": \"https://www.clf-lighting.com\",\n    \"rdmId\": 738\n  },\n  \"coemar\": {\n    \"name\": \"Coemar\",\n    \"website\": \"https://www.coemar.com/\",\n    \"rdmId\": 17229\n  },\n  \"contest\": {\n    \"name\": \"Contest\",\n    \"website\": \"https://www.contest-lighting.com/en/\"\n  },\n  \"dedolight\": {\n    \"name\": \"Dedolight\",\n    \"website\": \"https://www.dedoweigertfilm.de/dwf-en/brands/dedolight_overview.php\"\n  },\n  \"desisti\": {\n    \"name\": \"Desisti\",\n    \"website\": \"https://www.desisti.it\"\n  },\n  \"dmg-lumiere\": {\n    \"name\": \"DMG Lumière\",\n    \"website\": \"https://emea.rosco.com/en/products/brand/dmg-lighting\",\n    \"rdmId\": 13105\n  },\n  \"dts\": {\n    \"name\": \"DTS\",\n    \"website\": \"https://dts-lighting.it/\",\n    \"rdmId\": 1808\n  },\n  \"elation\": {\n    \"name\": \"Elation\",\n    \"website\": \"https://www.elationlighting.com/\",\n    \"rdmId\": 8870\n  },\n  \"eliminator\": {\n    \"name\": \"Eliminator Lighting\",\n    \"website\": \"https://www.adj.com/eliminator-lighting\"\n  },\n  \"empire-lighting\": {\n    \"name\": \"EMPiRE Lighting\",\n    \"website\": \"http://shop.empire-electronic.de/shop-EMPiRE.html\"\n  },\n  \"epsilon\": {\n    \"name\": \"Epsilon\",\n    \"website\": \"https://www.epsilon-pro.com/\"\n  },\n  \"equinox\": {\n    \"name\": \"Equinox\",\n    \"comment\": \"Brand of the Prolight Concepts Group.\",\n    \"website\": \"https://www.prolight.co.uk/catalogue/brand-results.aspx?bnd_id=693a0079-5e0a-42b1-86b1-aff800bd5d2c\"\n  },\n  \"etc\": {\n    \"name\": \"ETC\",\n    \"website\": \"https://www.etcconnect.com/\",\n    \"rdmId\": 25972\n  },\n  \"eurolite\": {\n    \"name\": \"Eurolite\",\n    \"website\": \"https://www.steinigke.de/en/Eurolite/\"\n  },\n  \"event-lighting\": {\n    \"name\": \"Event Lighting\",\n    \"website\": \"https://eventlighting.com.au/\"\n  },\n  \"evolight\": {\n    \"name\": \"Evolight\"\n  },\n  \"explo\": {\n    \"name\": \"Explo\",\n    \"website\": \"https://www.explo.at/en\"\n  },\n  \"eyourlife\": {\n    \"name\": \"Eyourlife\",\n    \"website\": \"https://www.eyourlife.com/\"\n  },\n  \"fiilex\": {\n    \"name\": \"Fiilex\",\n    \"website\": \"https://fiilex.com/\",\n    \"rdmId\": 24868\n  },\n  \"flash-professional\": {\n    \"name\": \"Flash Professional\",\n    \"website\": \"https://flash-butrym.pl/en_US/c/Professional-Series/91\"\n  },\n  \"fovitec\": {\n    \"name\": \"Fovitec\",\n    \"website\": \"https://web.archive.org/web/20240324222208/https://www.fovitec.com/\"\n  },\n  \"fractal-lights\": {\n    \"name\": \"Fractal Lights\",\n    \"website\": \"https://fractallights.com/\"\n  },\n  \"fun-generation\": {\n    \"name\": \"Fun Generation\",\n    \"website\": \"https://www.thomann.de/intl/fun_generation.html\"\n  },\n  \"futurelight\": {\n    \"name\": \"Futurelight\",\n    \"website\": \"https://www.steinigke.de/en/futurelight/\"\n  },\n  \"galaxis\": {\n    \"name\": \"Galaxis\",\n    \"comment\": \"Since 1992 we have been developing and manufacturing radio-operated firing systems and so we can offer you unlimited possibilities combined with the saving of material and working hours. Our goal was the synthesis of advantageous wireless firing with reliability and safety.\",\n    \"website\": \"https://www.firing-system.com/\"\n  },\n  \"gantom\": {\n    \"name\": \"Gantom\",\n    \"website\": \"https://www.gantom.com\"\n  },\n  \"generic\": {\n    \"name\": \"Generic\",\n    \"comment\": \"Use this pseudo manufacturer if you need to quick patch some channels without having to create a new fixture.\"\n  },\n  \"ghost\": {\n    \"name\": \"Ghost\",\n    \"comment\": \"Parent company MH Diffusion went out of business in Decemer 2019.\",\n    \"website\": \"https://www.youtube.com/channel/UC8RPLBCgAsJnDpmBZV-3WWA\"\n  },\n  \"glp\": {\n    \"name\": \"GLP\",\n    \"comment\": \"German Light Products\",\n    \"website\": \"https://glp.de/en/\",\n    \"rdmId\": 26476\n  },\n  \"glx\": {\n    \"name\": \"GLX\"\n  },\n  \"griven\": {\n    \"name\": \"Griven\",\n    \"website\": \"https://www.griven.com/\"\n  },\n  \"gruft\": {\n    \"name\": \"Gruft\",\n    \"comment\": \"Görli + Edelnörd\"\n  },\n  \"hazebase\": {\n    \"name\": \"Hazebase\",\n    \"website\": \"https://hazebase.com/\"\n  },\n  \"hive\": {\n    \"name\": \"Hive Lighting\",\n    \"website\": \"https://hivelighting.com\"\n  },\n  \"hong-yi\": {\n    \"name\": \"Hong Yi\",\n    \"website\": \"https://en.hongyilights.com/\"\n  },\n  \"hsl\": {\n    \"name\": \"HSL\",\n    \"website\": \"https://www.amazon.com/stores/HighIightSpIendidLife/page/C6F4337A-41CC-4560-880E-06BCA9E96924\"\n  },\n  \"ibiza-light\": {\n    \"name\": \"Ibiza light\",\n    \"website\": \"https://lotronic.net/gb/brand/16-ibiza\"\n  },\n  \"ignition\": {\n    \"name\": \"Ignition\",\n    \"comment\": \"Seems to be discontinued.\"\n  },\n  \"ikan\": {\n    \"name\": \"Ikan\",\n    \"website\": \"https://ikancorp.com/\"\n  },\n  \"infinity\": {\n    \"name\": \"Infinity\",\n    \"website\": \"https://www.highlite.com/en/brands/infinity.html\"\n  },\n  \"jb-lighting\": {\n    \"name\": \"JB-Lighting\",\n    \"website\": \"https://jb-lighting.de/\"\n  },\n  \"jb-systems\": {\n    \"name\": \"JB Systems\",\n    \"website\": \"https://jb-systems.eu/\"\n  },\n  \"kam\": {\n    \"name\": \"KAM\",\n    \"comment\": \"No website - no longer trading\"\n  },\n  \"kino-flo\": {\n    \"name\": \"Kino Flo\",\n    \"website\": \"https://kinoflo.com/\",\n    \"rdmId\": 19270\n  },\n  \"lalucenatz\": {\n    \"name\": \"LaluceNatz\"\n  },\n  \"laserworld\": {\n    \"name\": \"Laserworld\",\n    \"website\": \"https://www.laserworld.com/en/\"\n  },\n  \"ledj\": {\n    \"name\": \"LEDJ\",\n    \"comment\": \"Brand of the Prolight Concepts Group.\",\n    \"website\": \"https://www.prolight.co.uk/catalogue/brand-results.aspx?bnd_id=a46e50d8-13da-4112-95d7-aff800bd5d2c\"\n  },\n  \"lep-laser\": {\n    \"name\": \"LEP-LASER\",\n    \"comment\": \"Laser Entertainment Products\"\n  },\n  \"light-sky\": {\n    \"name\": \"LIGHT SKY\",\n    \"website\": \"https://en.lightsky.com.cn/\",\n    \"rdmId\": 14472\n  },\n  \"light4me\": {\n    \"name\": \"Light4me\",\n    \"website\": \"https://light4me.pl/\"\n  },\n  \"lightmaxx\": {\n    \"name\": \"lightmaXX\",\n    \"website\": \"https://www.musicstore.de/en_DE/EUR/brands/lightmaxx\"\n  },\n  \"lite-tek\": {\n    \"name\": \"Lite-Tek\",\n    \"website\": \"https://lite-tek.com.mx/\"\n  },\n  \"litecraft\": {\n    \"name\": \"Litecraft\",\n    \"website\": \"https://lmp.de/marken/litecraft/\"\n  },\n  \"litegear\": {\n    \"name\": \"LiteGear\",\n    \"website\": \"https://www.litegear.com/\"\n  },\n  \"lixada\": {\n    \"name\": \"Lixada\",\n    \"website\": \"https://www.lixada.com/\"\n  },\n  \"look\": {\n    \"name\": \"Look Solutions\",\n    \"website\": \"https://www.looksolutions.com/\"\n  },\n  \"lupo\": {\n    \"name\": \"Lupo\",\n    \"website\": \"https://www.lupo.it/en/\"\n  },\n  \"magicfx\": {\n    \"name\": \"MagicFX\",\n    \"website\": \"https://www.magicfx.eu/\",\n    \"rdmId\": 18008\n  },\n  \"mark\": {\n    \"name\": \"Mark\",\n    \"comment\": \"No manufacturer website available, linking to distributor Equipson instead.\",\n    \"website\": \"https://products.equipson.es/mark\"\n  },\n  \"martin\": {\n    \"name\": \"Martin\",\n    \"website\": \"https://www.martin.com/en-US\",\n    \"rdmId\": 19792\n  },\n  \"mdg\": {\n    \"name\": \"MDG\",\n    \"website\": \"https://www.mdgfog.com/en\",\n    \"rdmId\": 19780\n  },\n  \"mega-led-lighting\": {\n    \"name\": \"Mega LED Lighting\",\n    \"website\": \"https://www.mjledlighting.com/\"\n  },\n  \"mega-lite\": {\n    \"name\": \"MegaLite\",\n    \"website\": \"https://www.mega.lighting/\"\n  },\n  \"minuit-une\": {\n    \"name\": \"Minuit Une\",\n    \"website\": \"https://minuitune.com/\"\n  },\n  \"nicols\": {\n    \"name\": \"Nicols\",\n    \"website\": \"https://nicols-lighting.fr/\"\n  },\n  \"orion\": {\n    \"name\": \"Orion Effects Lighting\",\n    \"website\": \"https://orion-fxlights.com/\"\n  },\n  \"panasonic\": {\n    \"name\": \"Panasonic\",\n    \"website\": \"https://panasonic.net/cns/projector/\"\n  },\n  \"phocea-light\": {\n    \"name\": \"Phocea Light\",\n    \"website\": \"https://www.phocealight.fr/\"\n  },\n  \"powerlighting\": {\n    \"name\": \"Power Lighting\"\n  },\n  \"pr-lighting\": {\n    \"name\": \"PR LIGHTING\",\n    \"website\": \"http://www.pr-lighting.com/\"\n  },\n  \"prolights\": {\n    \"name\": \"Prolights\",\n    \"website\": \"https://prolights.it/\",\n    \"rdmId\": 5584\n  },\n  \"qtx\": {\n    \"name\": \"QTX\",\n    \"website\": \"https://www.avsl.com/brands/qtx\"\n  },\n  \"renkforce\": {\n    \"name\": \"Renkforce\",\n    \"comment\": \"Store brand of German electronics retailer Conrad.\",\n    \"website\": \"https://www.conrad.at/de/marken/renkforce.html\"\n  },\n  \"robe\": {\n    \"name\": \"Robe\",\n    \"website\": \"https://www.robe.cz/\",\n    \"rdmId\": 21075\n  },\n  \"robert-juliat\": {\n    \"name\": \"Robert Juliat\",\n    \"website\": \"https://www.robertjuliat.com/\"\n  },\n  \"rockville\": {\n    \"name\": \"Rockville\",\n    \"website\": \"https://www.rockvilleaudio.com/\"\n  },\n  \"sgm\": {\n    \"name\": \"SGM\",\n    \"website\": \"https://sgmlight.com/\",\n    \"rdmId\": 21319\n  },\n  \"shehds\": {\n    \"name\": \"Shehds\",\n    \"website\": \"https://shehds.com/\"\n  },\n  \"showline\": {\n    \"name\": \"Showline\",\n    \"website\": \"https://www.vari-lite.com/global\",\n    \"comment\": \"Belongs to the Vari-Lite brand.\"\n  },\n  \"showlite\": {\n    \"name\": \"Showlite\",\n    \"website\": \"https://www.kirstein.de/en/By-Brand/Showlite/\"\n  },\n  \"showpro\": {\n    \"name\": \"ShowPRO\",\n    \"website\": \"https://www.showtech.com.au/our-brands/showpro/\"\n  },\n  \"showtec\": {\n    \"name\": \"Showtec\",\n    \"website\": \"https://www.highlite.com/en/brands/showtec.html\",\n    \"rdmId\": 10676\n  },\n  \"showven\": {\n    \"name\": \"Showven\",\n    \"website\": \"https://showven.en.alibaba.com/\"\n  },\n  \"silver-star\": {\n    \"name\": \"Silver Star\",\n    \"comment\": \"Brand of Guangzhou Yajiang Photoelectric Equipment Co., Ltd.\",\n    \"website\": \"https://www.yajiang.cn/en/home2\"\n  },\n  \"skypix\": {\n    \"name\": \"Skypix\",\n    \"website\": \"https://skypixlight.com.br/\"\n  },\n  \"smoke-factory\": {\n    \"name\": \"Smoke Factory\",\n    \"website\": \"https://smoke-factory.de/\"\n  },\n  \"solaris\": {\n    \"name\": \"Solaris\"\n  },\n  \"solena\": {\n    \"name\": \"Solena\",\n    \"comment\": \"Store brand of electronics retailer ProSound And Stage Lighting.\",\n    \"website\": \"https://shop.solotech.com/en-uk/collections/solena-professional\"\n  },\n  \"soundlight\": {\n    \"name\": \"SoundLight\",\n    \"website\": \"https://soundlight.de/\",\n    \"rdmId\": 21324\n  },\n  \"stage-right\": {\n    \"name\": \"Stage Right\",\n    \"comment\": \"Store brand of Monoprice\",\n    \"website\": \"https://www.monoprice.com/\"\n  },\n  \"stairville\": {\n    \"name\": \"Stairville\",\n    \"website\": \"https://www.thomann.de/intl/stairville.html\"\n  },\n  \"starway\": {\n    \"name\": \"Starway\",\n    \"website\": \"https://en.starway.eu/\",\n    \"rdmId\": 2537\n  },\n  \"studio-due\": {\n    \"name\": \"Studio Due\",\n    \"website\": \"https://www.studiodue.com/\"\n  },\n  \"sun-star\": {\n    \"name\": \"Sun Star\",\n    \"website\": \"https://www.sunstarprolight.com/\"\n  },\n  \"tecshow\": {\n    \"name\": \"Tecshow\",\n    \"comment\": \"Lighting Brand of AMPRO\",\n    \"website\": \"http://tecshow.amproweb.com/en/\"\n  },\n  \"tiptop-stage-light\": {\n    \"name\": \"TIPTOP Stage Light\",\n    \"website\": \"https://www.tiptopstagelight.com/\"\n  },\n  \"tmb\": {\n    \"name\": \"TMB\",\n    \"website\": \"https://tmb.com/\",\n    \"rdmId\": 6906\n  },\n  \"tomshine\": {\n    \"name\": \"Tomshine\",\n    \"website\": \"https://www.tomshine.com\"\n  },\n  \"uking\": {\n    \"name\": \"U`King\",\n    \"website\": \"https://www.uking-online.com/\"\n  },\n  \"ultratec\": {\n    \"name\": \"Ultratec\",\n    \"website\": \"https://ultratecfx.com\",\n    \"rdmId\": 19533\n  },\n  \"varytec\": {\n    \"name\": \"Varytec\",\n    \"website\": \"https://www.thomann.de/intl/varytec.html\"\n  },\n  \"velleman\": {\n    \"name\": \"Velleman\",\n    \"website\": \"https://www.velleman.eu/\"\n  },\n  \"venue\": {\n    \"name\": \"Venue\",\n    \"comment\": \"Venue by Proline\",\n    \"website\": \"https://venuelightingeffects.com/\"\n  },\n  \"vrsl\": {\n    \"name\": \"VR Stage Lighting\",\n    \"website\": \"https://github.com/AcChosen/VR-Stage-Lighting\"\n  }\n}\n"
  },
  {
    "path": "fixtures/mark/mbar-381-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MBAR 381 IP\",\n  \"shortName\": \"MarkMBar381IP\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Gerard Fontanillas\"],\n    \"createDate\": \"2019-03-04\",\n    \"lastModifyDate\": \"2019-03-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.eafg.es/productos/Docs/Manuales/MBAR381IP_MANUAL_V161001_20161028134808.pdf\"\n    ],\n    \"productPage\": [\n      \"https://products.equipson.es/mbar-381-ip\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1001, 68.78, 100],\n    \"weight\": 4.1,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [18, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 20],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"not synchronous\"\n        },\n        {\n          \"dmxRange\": [21, 60],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"synchronous\"\n        },\n        {\n          \"dmxRange\": [61, 100],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"electronic sinewave\"\n        },\n        {\n          \"dmxRange\": [101, 140],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [141, 180],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [181, 220],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"electronic squarewave\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT01\"\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT02\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT03\"\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT04\"\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT05\"\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT06\"\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT07\"\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT08\"\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT09\"\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CT10\"\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Red-Green-Blue-Yellow-Magenta-Cyan-White\"\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Red-Green-Blue\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Red-Green, Red-Blue, Green-Blue\"\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Red-Yellow-White-Cyan-Blue\"\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Rainbow\"\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Violet\",\n          \"colors\": [\"#aa00ff\"]\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Golden\",\n          \"colors\": [\"#ffcc00\"]\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"5500K\"\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [12, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Cyan\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [52, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Green\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [91, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [92, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Yellow\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [131, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [132, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Red\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [172, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Magenta\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [212, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Blue\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use menu setting\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear curve\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square law curve\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse square law curve\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-curve\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear curve and smooth\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Square law curve and smooth\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverse square law curve and smooth\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-curve and smooth\"\n        },\n        {\n          \"dmxRange\": [91, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Use menu setting\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe\",\n        \"Color Presets\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Macro Speed\",\n        \"Color Presets\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mark/superbat-led-72.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SUPERBAT LED 72\",\n  \"shortName\": \"MarkSuperBat72\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Gerard Fontanillas\"],\n    \"createDate\": \"2019-03-04\",\n    \"lastModifyDate\": \"2019-03-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.eafg.es/productos/Docs/Manuales/SUPERBAT_LED_72_MANUAL_20160920113641.pdf\"\n    ],\n    \"productPage\": [\n      \"https://products.equipson.es/superbat-led-72\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [135, 135, 210],\n    \"weight\": 2.5,\n    \"power\": 140,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"6x 12W RGBWAUV LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"helpWanted\": \"Can the speed be controlled by the exact DMX value (1=slow, 255=fast; or vice-versa)?\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mixing\",\n          \"helpWanted\": \"What does this capability do?\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [50, 69],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Gradual\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Mutation\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [130, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [150, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [170, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [190, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"UV\"\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [230, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 3\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Does this control the speed of the effects in the Programs channel is this strobe speed?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Programs\",\n        \"Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/atomic-3000.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Atomic 3000\",\n  \"shortName\": \"MartinAt3000\",\n  \"categories\": [\"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-01-20\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/35000094G%20UM_Atomic3000DMX_EN_G.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=GMW1aEkfQYQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [450, 239, 234],\n    \"weight\": 7.5,\n    \"power\": 3000,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Xenon 3000W\",\n      \"colorTemperature\": 5600\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"highlightValue\": 249,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [6, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Blind\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"dark\",\n          \"brightnessEnd\": \"bright\"\n        }\n      ]\n    },\n    \"Flash Duration\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"650ms\"\n      }\n    },\n    \"Flash Rate\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Single Flash\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [6, 42],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [43, 85],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [86, 128],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [129, 171],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [172, 214],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [215, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Flash Duration\",\n        \"Flash Rate\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Flash Duration\",\n        \"Flash Rate\",\n        \"Effects\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-250-beam.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC 250 Beam\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Florian Edelmann\"],\n    \"createDate\": \"2019-10-31\",\n    \"lastModifyDate\": \"2019-10-31\"\n  },\n  \"comment\": \"Can be converted from a MAC 250 Wash with a MAC 250 Beam Kit, i.e. color filters are removed and beam effect gobos are inserted in the color wheel.\",\n  \"links\": {\n    \"manual\": [\n      \"https://adn.harmanpro.com/site_elements/executables/5846_1526694942/UM_MAC250Wash_EN_G_original.pdf\",\n      \"https://adn.harmanpro.com/site_elements/executables/3354_1526062748/INST_MAC250BeamKit_EN_G_original.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/mac-250-beam\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2obCQerSMPg\",\n      \"https://www.youtube.com/watch?v=3qYMqdxzuQQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [393, 538, 315],\n    \"weight\": 22.9,\n    \"power\": 326,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"250W discharge lamp (standard: Philips MSD 250/2)\",\n      \"colorTemperature\": 8500,\n      \"lumens\": 7700\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25.9, 48.8]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"50%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"25%\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Beam two dots\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Beam three dots\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Beam two bars 10\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Beamcone 15\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 72],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [73, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 147],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [148, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"50%\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [168, 187],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [188, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [191, 193],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [194, 196],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [197, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [203, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [208, 217],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset fixture\"\n        },\n        {\n          \"dmxRange\": [218, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [228, 237],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp On\"\n        },\n        {\n          \"dmxRange\": [238, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp Off\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan Intensity\": {\n      \"fineChannelAliases\": [\"Cyan Intensity fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Random Cyan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Cyan range\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Minimum Cyan setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Maximum Cyan setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Cyan range\"\n        }\n      ]\n    },\n    \"Magenta Intensity\": {\n      \"fineChannelAliases\": [\"Magenta Intensity fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Random Magenta\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Magenta range\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Minimum Magenta setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Maximum Magenta setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Magenta range\"\n        }\n      ]\n    },\n    \"Yellow Intensity\": {\n      \"fineChannelAliases\": [\"Yellow Intensity fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Random Yellow\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Yellow range\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Minimum Yellow setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Maximum Yellow setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Yellow range\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"fineChannelAliases\": [\"Gobo Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [27, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [78, 102],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 128],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [129, 152],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [153, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 226],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [227, 245],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY color\",\n          \"speed\": \"fast\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random Cyan\",\n            \"Magenta\": \"Random Magenta\",\n            \"Yellow\": \"Random Yellow\"\n          }\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY color\",\n          \"comment\": \"Medium\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random Cyan\",\n            \"Magenta\": \"Random Magenta\",\n            \"Yellow\": \"Random Yellow\"\n          }\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY color\",\n          \"speed\": \"slow\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random Cyan\",\n            \"Magenta\": \"Random Magenta\",\n            \"Yellow\": \"Random Yellow\"\n          }\n        }\n      ]\n    },\n    \"Frost\": {\n      \"fineChannelAliases\": [\"Frost fine\"],\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"257deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [3, 242],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [243, 245],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking mode\"\n        },\n        {\n          \"dmxRange\": [3, 245],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Vector mode\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking, effect wheels do not cross open position\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking, effect wheels turn shortest distance\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Vector mode\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-Bit\",\n      \"shortName\": \"16Bt\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Gobo Wheel\",\n        \"Frost\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Effect Speed\"\n      ]\n    },\n    {\n      \"name\": \"16-Bit Extendend\",\n      \"shortName\": \"16Ex\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Cyan\",\n        \"Cyan Intensity fine\",\n        \"Magenta\",\n        \"Magenta Intensity fine\",\n        \"Yellow\",\n        \"Yellow Intensity fine\",\n        \"Gobo Wheel\",\n        \"Gobo Wheel fine\",\n        \"Frost\",\n        \"Frost fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-250-krypton.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mac 250 Krypton\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Teichi\"],\n    \"createDate\": \"2019-10-08\",\n    \"lastModifyDate\": \"2019-10-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adn.harmanpro.com/site_elements/executables/5646_1526694591/UM_MAC250KryptonEntour_EN_K_original.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/mac-250-krypton\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=HUzUeKIRmVo\",\n      \"https://www.youtube.com/watch?v=gdBW29YXsuM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [393, 538, 315],\n    \"weight\": 22.4,\n    \"power\": 326,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Halogen\",\n      \"colorTemperature\": 8500,\n      \"lumens\": 5000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20.1, 20.1]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colorTemperature\": \"CTB\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow 603\",\n          \"colors\": [\"#ede04b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 104\",\n          \"colors\": [\"#1e4f6f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink 312\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green 206\",\n          \"colors\": [\"#97cda9\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 108\",\n          \"colors\": [\"#3b4875\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red 301\",\n          \"colors\": [\"#cb301e\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta 507\",\n          \"colors\": [\"#8e507e\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 101\",\n          \"colors\": [\"#385287\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange 306\",\n          \"colors\": [\"#ffa500\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Darkgreen\",\n          \"colors\": [\"#006400\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple 502\",\n          \"colors\": [\"#a666ea\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Eclipse\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Fat bar\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Fan\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Happy Yins\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Twisted triangle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Splash\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Affobet\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Maintenance\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 72],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [73, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 187],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [188, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [191, 196],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [197, 202],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [203, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [208, 217],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [218, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [228, 237],\n          \"type\": \"Maintenance\",\n          \"hold\": \"2s\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [238, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"2s\",\n          \"comment\": \"Lamp off\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [11, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [22, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [33, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [44, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [55, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [66, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [77, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [88, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [99, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [110, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [121, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [132, 142],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 13,\n          \"slotNumberEnd\": 14\n        },\n        {\n          \"dmxRange\": [143, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [208, 226],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [227, 245],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [43, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [59, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [74, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [82, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [97, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 134],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [135, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [165, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 194],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [195, 209],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 232],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\",\n          \"switchChannels\": {\n            \"Gobo Rotation\": \"Gobo Rotation Angle\",\n            \"Gobo Rotation fine\": \"Gobo Rotation Angle fine\"\n          }\n        }\n      ]\n    },\n    \"Gobo Rotation Angle\": {\n      \"fineChannelAliases\": [\"Gobo Rotation Angle fine\"],\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"395deg\"\n      }\n    },\n    \"Gobo Rotation Speed\": {\n      \"fineChannelAliases\": [\"Gobo Rotation Speed fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [3, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 252],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"20m\",\n        \"distanceEnd\": \"2m\"\n      }\n    },\n    \"Prism / Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No prism\"\n        },\n        {\n          \"dmxRange\": [20, 79],\n          \"type\": \"Prism\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [90, 149],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [150, 215],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No prism\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 1\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 2\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 3\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 4\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 5\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 6\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 7\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo macro 8\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"257deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [3, 242],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [243, 245],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Override menu setting PTSP=SLOW\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Override menu setting PTSP=NORM\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Override menu setting PTSP=FAST\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    },\n    \"Dimmer/Focus/Color/Gobo/Prism Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [3, 245],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Override menu setting SCUT=OFF\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Override menu setting SCUT=ON\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-Bit\",\n      \"shortName\": \"16BT\",\n      \"channels\": [\n        \"Shutter / Maintenance\",\n        \"Dimmer\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Focus\",\n        \"Prism / Macros\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer/Focus/Color/Gobo/Prism Speed\"\n      ]\n    },\n    {\n      \"name\": \"16-Bit Extended\",\n      \"shortName\": \"16EX\",\n      \"channels\": [\n        \"Shutter / Maintenance\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Prism / Macros\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer/Focus/Color/Gobo/Prism Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-250-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC 250 Wash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Nicolas\", \"Florian Edelmann\"],\n    \"createDate\": \"2019-10-31\",\n    \"lastModifyDate\": \"2019-10-31\"\n  },\n  \"comment\": \"Can be converted to a MAC 250 Beam with a MAC 250 Beam Kit, i.e. color filters are removed and beam effect gobos are inserted in the color wheel.\",\n  \"links\": {\n    \"manual\": [\n      \"https://adn.harmanpro.com/site_elements/executables/5846_1526694942/UM_MAC250Wash_EN_G_original.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/mac-250-wash\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=6pt5-Sw3YVc\",\n      \"https://www.youtube.com/watch?v=3qYMqdxzuQQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [393, 538, 315],\n    \"weight\": 22.9,\n    \"power\": 326,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"250W discharge lamp (standard: Philips MSD 250/2)\",\n      \"colorTemperature\": 8500,\n      \"lumens\": 7700\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25.9, 48.8]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTC 5500\",\n          \"colorTemperature\": \"2900K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink 312\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red 308\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green 206\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 108\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 72],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [73, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 147],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [148, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"50%\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [168, 187],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [188, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [191, 193],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [194, 196],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [197, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [203, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [208, 217],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset fixture\"\n        },\n        {\n          \"dmxRange\": [218, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [228, 237],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp On\"\n        },\n        {\n          \"dmxRange\": [238, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp Off\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan Intensity\": {\n      \"fineChannelAliases\": [\"Cyan Intensity fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Random Cyan\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Cyan range\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Minimum Cyan setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Maximum Cyan setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Cyan range\"\n        }\n      ]\n    },\n    \"Magenta Intensity\": {\n      \"fineChannelAliases\": [\"Magenta Intensity fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Random Magenta\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Magenta range\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Minimum Magenta setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Maximum Magenta setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Magenta range\"\n        }\n      ]\n    },\n    \"Yellow Intensity\": {\n      \"fineChannelAliases\": [\"Yellow Intensity fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Random Yellow\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Yellow range\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Minimum Yellow setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"EffectParameter\",\n          \"comment\": \"Maximum Yellow setting\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Full Yellow range\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [27, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [78, 102],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 128],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [129, 152],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [153, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 226],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [227, 245],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\"\n          }\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY color\",\n          \"speed\": \"fast\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random Cyan\",\n            \"Magenta\": \"Random Magenta\",\n            \"Yellow\": \"Random Yellow\"\n          }\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY color\",\n          \"comment\": \"Medium\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random Cyan\",\n            \"Magenta\": \"Random Magenta\",\n            \"Yellow\": \"Random Yellow\"\n          }\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY color\",\n          \"speed\": \"slow\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random Cyan\",\n            \"Magenta\": \"Random Magenta\",\n            \"Yellow\": \"Random Yellow\"\n          }\n        }\n      ]\n    },\n    \"Frost\": {\n      \"fineChannelAliases\": [\"Frost fine\"],\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"257deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [3, 242],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [243, 245],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking mode\"\n        },\n        {\n          \"dmxRange\": [3, 245],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Vector mode\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking, effect wheels do not cross open position\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking, effect wheels turn shortest distance\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Vector mode\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-Bit\",\n      \"shortName\": \"16Bt\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Wheel\",\n        \"Frost\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Effect Speed\"\n      ]\n    },\n    {\n      \"name\": \"16-Bit Extendend\",\n      \"shortName\": \"16Ex\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Cyan\",\n        \"Cyan Intensity fine\",\n        \"Magenta\",\n        \"Magenta Intensity fine\",\n        \"Yellow\",\n        \"Yellow Intensity fine\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Frost\",\n        \"Frost fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-600.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC 600\",\n  \"shortName\": \"MAC 600\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Karl Humbug\"],\n    \"createDate\": \"2018-09-25\",\n    \"lastModifyDate\": \"2019-03-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adn.harmanpro.com/site_elements/executables/3027_1526061584/UM_MAC600_EN_H_original.PDF\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en-US/products/mac-600\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [481, 610, 456],\n    \"weight\": 31.5,\n    \"power\": 750,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"Osram HSR-575/2\",\n      \"colorTemperature\": 6000,\n      \"lumens\": 21500\n    },\n    \"lens\": {\n      \"name\": \"Fresnel\",\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Strobe / Reset / Lamp\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 112],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"8Hz\",\n          \"speedEnd\": \"0Hz\"\n        },\n        {\n          \"dmxRange\": [113, 115],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [116, 122],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Reduced lamp power (MAC 600 E)\"\n        },\n        {\n          \"dmxRange\": [123, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [128, 147],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [148, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"50%\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [168, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [208, 217],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset fixture\"\n        },\n        {\n          \"dmxRange\": [218, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [228, 237],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp power on\"\n        },\n        {\n          \"dmxRange\": [238, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Lamp power off\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 40],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [81, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [121, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [186, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Beam Shaper 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"BladeInsertion\",\n          \"blade\": 1,\n          \"insertionStart\": \"out\",\n          \"insertionEnd\": \"in\",\n          \"comment\": \"Beam shaper left…right\"\n        }\n      ]\n    },\n    \"Beam Shaper 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [3, 170],\n          \"type\": \"BladeInsertion\",\n          \"blade\": 2,\n          \"insertionStart\": \"out\",\n          \"insertionEnd\": \"in\",\n          \"comment\": \"Beam shaper left…right\"\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"440deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"306deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Tracking (default speed)\"\n        },\n        {\n          \"dmxRange\": [3, 245],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    },\n    \"Dimmer / CMY / Color Wheel / Beam Shaper speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Tracking (default speed)\"\n        },\n        {\n          \"dmxRange\": [3, 239],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [240, 242],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking, studio mode off\"\n        },\n        {\n          \"dmxRange\": [243, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking, studio mode on\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking, shortcuts off\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking, shortcuts on\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"DMX1 (10-channel)\",\n      \"shortName\": \"DMX1\",\n      \"channels\": [\n        \"Shutter / Strobe / Reset / Lamp\",\n        \"Intensity\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Wheel\",\n        \"Beam Shaper 1\",\n        \"Beam Shaper 2\",\n        \"Pan\",\n        \"Tilt\"\n      ]\n    },\n    {\n      \"name\": \"DMX2 (12-channel)\",\n      \"shortName\": \"DMX2\",\n      \"channels\": [\n        \"Shutter / Strobe / Reset / Lamp\",\n        \"Intensity\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Wheel\",\n        \"Beam Shaper 1\",\n        \"Beam Shaper 2\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\"\n      ]\n    },\n    {\n      \"name\": \"DMX3 (12-channel)\",\n      \"shortName\": \"DMX3\",\n      \"channels\": [\n        \"Shutter / Strobe / Reset / Lamp\",\n        \"Intensity\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Wheel\",\n        \"Beam Shaper 1\",\n        \"Beam Shaper 2\",\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer / CMY / Color Wheel / Beam Shaper speed\"\n      ]\n    },\n    {\n      \"name\": \"DMX4 (14-channel)\",\n      \"shortName\": \"DMX4\",\n      \"channels\": [\n        \"Shutter / Strobe / Reset / Lamp\",\n        \"Intensity\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Wheel\",\n        \"Beam Shaper 1\",\n        \"Beam Shaper 2\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer / CMY / Color Wheel / Beam Shaper speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-700-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC 700 Wash\",\n  \"shortName\": \"MartinMAC700Wash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Karl Humbug\"],\n    \"createDate\": \"2018-07-17\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adn.harmanpro.com/site_elements/executables/5949_1526695117/UM_MAC700Wash_EN_D_original.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=FvGsX6qC348\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [365, 656, 450],\n    \"weight\": 32,\n    \"power\": 950,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"OSRAMHTI700/D4/75\",\n      \"colorTemperature\": 7500,\n      \"lumens\": 18700\n    },\n    \"lens\": {\n      \"name\": \"Fresnel\",\n      \"degreesMinMax\": [12.5, 66]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 110\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green 206 IAD\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink 312\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange 306M\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Half minus green\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO 3200-4100K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red 308\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 72],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [73, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 147],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [148, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"50%\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [168, 187],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [188, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [191, 193],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [194, 196],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [197, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [203, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [208, 217],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset fixture\"\n        },\n        {\n          \"dmxRange\": [218, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [228, 237],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [238, 242],\n          \"type\": \"Maintenance\",\n          \"comment\": \"400W mode\"\n        },\n        {\n          \"dmxRange\": [243, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"700W mode\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan Intensity\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta Intensity\": {\n      \"fineChannelAliases\": [\"Magenta fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow Intensity\": {\n      \"fineChannelAliases\": [\"Yellow fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Random CMY Cyan Range\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal (full range)\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Minimum cyan setting 0…100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Maximum cyan setting 0…100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal (full range)\"\n        }\n      ]\n    },\n    \"Random CMY Magenta Range\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal (full range)\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Minimum magenta setting 0…100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Maximum magenta setting 0…100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal (full range)\"\n        }\n      ]\n    },\n    \"Random CMY Yellow Range\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal (full range)\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Minimum yellow setting 0…100%\"\n        },\n        {\n          \"dmxRange\": [128, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Maximum yellow setting 0…100%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal (full range)\"\n        }\n      ]\n    },\n    \"CTO\": {\n      \"fineChannelAliases\": [\"CTO fine\"],\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"default\",\n        \"colorTemperatureEnd\": \"warm\",\n        \"helpWanted\": \"Is it really CTO (correct to orange)? The manual just mentions CTC (color temperature correction).\"\n      }\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [35, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [52, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [69, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [86, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [103, 118],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [119, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [137, 152],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [153, 153],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [154, 158],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [159, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [164, 168],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [169, 173],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [174, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [179, 183],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [184, 188],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [189, 193],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [194, 198],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [199, 219],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [220, 240],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Beamshaper Angle\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No beam shaper\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        }\n      ]\n    },\n    \"Beamshaper Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No beam shaper\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\",\n            \"Beamshaper\": \"Beamshaper Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel shake\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\",\n            \"Beamshaper\": \"Beamshaper Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Beam shaper continuous rotation\",\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\",\n            \"Beamshaper\": \"Beamshaper Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel shake\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"plus beam shaper continuous rotation\",\n          \"switchChannels\": {\n            \"Cyan\": \"Cyan Intensity\",\n            \"Magenta\": \"Magenta Intensity\",\n            \"Yellow\": \"Yellow Intensity\",\n            \"Beamshaper\": \"Beamshaper Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY\",\n          \"speed\": \"fast\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random CMY Cyan Range\",\n            \"Magenta\": \"Random CMY Magenta Range\",\n            \"Yellow\": \"Random CMY Yellow Range\",\n            \"Beamshaper\": \"Beamshaper Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY\",\n          \"speed\": \"50%\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random CMY Cyan Range\",\n            \"Magenta\": \"Random CMY Magenta Range\",\n            \"Yellow\": \"Random CMY Yellow Range\",\n            \"Beamshaper\": \"Beamshaper Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random CMY\",\n          \"speed\": \"slow\",\n          \"switchChannels\": {\n            \"Cyan\": \"Random CMY Cyan Range\",\n            \"Magenta\": \"Random CMY Magenta Range\",\n            \"Yellow\": \"Random CMY Yellow Range\",\n            \"Beamshaper\": \"Beamshaper Angle\"\n          }\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"246deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Tracking mode (default speed)\"\n        },\n        {\n          \"dmxRange\": [3, 242],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"vector mode\"\n        },\n        {\n          \"dmxRange\": [243, 245],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\",\n          \"comment\": \"tracking mode\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"50%\",\n          \"comment\": \"tracking mode\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"tracking mode\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    },\n    \"Effects Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Tracking mode\"\n        },\n        {\n          \"dmxRange\": [3, 245],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"vector mode\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking mode (color wheel does not turn shortest distance)\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking mode (color wheel turns shortest distance)\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic 16-channel\",\n      \"shortName\": \"basic16ch\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Beamshaper\",\n        \"Macros\",\n        \"Zoom\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Effects Speed\"\n      ]\n    },\n    {\n      \"name\": \"Extended 23-channel\",\n      \"shortName\": \"ext23ch\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\",\n        \"CTO\",\n        \"CTO fine\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Beamshaper\",\n        \"Macros\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Effects Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-aura.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC Aura\",\n  \"shortName\": \"MartinAura\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-08-03\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"comment\": \"moving wash:\\n- single-lens wash with fully premixed color \\n- broad color palette, RGBW color mixing \\n- eye-candy Aura EffectsTM\\nNote: If \\\"Color Calib\\\" (see settings) is enabled, \\\"Beam White\\\" has no effect – white LEDs are activated by RGB mixing\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_MACAura_EN_B.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/mac-aura\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=PKBiIK7Yr1E\",\n      \"https://www.youtube.com/watch?v=8kL6YO1U70Q\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 4\n  },\n  \"physical\": {\n    \"dimensions\": [302, 360, 302],\n    \"weight\": 5.6,\n    \"power\": 260,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 10000,\n      \"lumens\": 3850\n    },\n    \"lens\": {\n      \"name\": \"beam&aura\",\n      \"degreesMinMax\": [11, 58]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [25, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Sine wave\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [230, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Beam dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"232deg\"\n      }\n    },\n    \"Fixture control settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset entire fixture\"\n        },\n        {\n          \"dmxRange\": [15, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PTSP = NORM\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PTSP = FAST\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PTSP = SLOW\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode FULL\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode REGULATED\"\n        },\n        {\n          \"dmxRange\": [75, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Calibrated color output mode COLOR CALIB = ON\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Raw color output mode COLOR CALIB = OFF\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fast dimming, speed of changes unrestricted\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth dimming, speed of changes restricted slightly\"\n        },\n        {\n          \"dmxRange\": [125, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Illuminate display\"\n        }\n      ]\n    },\n    \"Beam color wheel effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffeb34\"],\n          \"comment\": \"LEE 790 - Moroccan Pink\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d68630\"],\n          \"comment\": \"LEE 157 - Pink\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff002c\"],\n          \"comment\": \"LEE 332 - Special rose Pink\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff3b71\"],\n          \"comment\": \"LEE 328 - Follies Pink\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8adb\"],\n          \"comment\": \"LEE 345 - Fuchsia Pink\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e2afe2\"],\n          \"comment\": \"LEE 194 - Surprise Pink\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2801ff\"],\n          \"comment\": \"LEE 181 - Congo Blue\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"LEE 071 - Tokyo Blue\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#004eff\"],\n          \"comment\": \"LEE 120 - Deep Blue\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00c7ff\"],\n          \"comment\": \"LEE 079 - Just Blue\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffea\"],\n          \"comment\": \"LEE 132 - Medium Blue\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#95f6ff\"],\n          \"comment\": \"LEE 200 - Double CT Blue\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#89ffe3\"],\n          \"comment\": \"LEE 161 - State Blue\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d5dcde\"],\n          \"comment\": \"LEE 201 - Full CT Blue\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbe8af\"],\n          \"comment\": \"LEE 202 - Half CT Blue\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cdffc7\"],\n          \"comment\": \"LEE 117 - Steel Blue\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#73ffa5\"],\n          \"comment\": \"LEE 353 - Lighter Blue\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#06ff8f\"],\n          \"comment\": \"LEE 118 - Light Blue\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff5e\"],\n          \"comment\": \"LEE 116 - Medium Blue Green\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#1dff00\"],\n          \"comment\": \"LEE 124 - Dark Green\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#20df00\"],\n          \"comment\": \"LEE 139 - Primary Green\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4bff00\"],\n          \"comment\": \"LEE 089 - Moss Green\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50e800\"],\n          \"comment\": \"LEE 122 - Fern Green\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6ce200\"],\n          \"comment\": \"LEE 738 - JAS Green\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#91c200\"],\n          \"comment\": \"LEE 088 - Lime Green\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d2ff00\"],\n          \"comment\": \"LEE 100 - Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e1e800\"],\n          \"comment\": \"LEE 104 - Deep Amber\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#17d700\"],\n          \"comment\": \"LEE 179 - Chrome Orange\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f7d600\"],\n          \"comment\": \"LEE 105 - Orange\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa300\"],\n          \"comment\": \"LEE 021 - Gold Amber\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9800\"],\n          \"comment\": \"LEE 778 - Millennium Gold\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6c00\"],\n          \"comment\": \"LEE 135 - Deep Golden Amber\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff5000\"],\n          \"comment\": \"LEE 164 - Flame Red\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [180, 201],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Virtual color wheel rotation\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\",\n          \"comment\": \"Virtual color wheel rotation\"\n        },\n        {\n          \"dmxRange\": [208, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\",\n          \"comment\": \"Virtual color wheel rotation\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Beam red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Beam green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Beam blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Beam white\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Beam CTC\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"10000K\",\n          \"colorTemperatureEnd\": \"2500K\"\n        }\n      ]\n    },\n    \"FX1 select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Idle\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dimmer sync\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [13, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe sync\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 18],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dimmer + strobe sync\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [19, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura color sync\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [22, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura all sync\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 39],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 42],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura strobe delay\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Trigger Delay\"\n          }\n        },\n        {\n          \"dmxRange\": [43, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe alternate single\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe alternate dual\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe alternate triple\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"3-step strobe\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 60],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity random alternate\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 66],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura ramp, Beam flash\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [67, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Beam ramp, Aura flash\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 72],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity Aura, Beam ramp\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [73, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity Beam, Aura ramp\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [76, 99],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 102],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura color offset\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Color offset\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 108],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [109, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hue shimmer\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Amount\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Saturation shimmer\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Amount\"\n          }\n        },\n        {\n          \"dmxRange\": [115, 126],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color strobe\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color offset strobe\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Color offset\"\n          }\n        },\n        {\n          \"dmxRange\": [133, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura color strobe\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 138],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura color offset strobe\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Color offset\"\n          }\n        },\n        {\n          \"dmxRange\": [139, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color spikes\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Strength\"\n          }\n        },\n        {\n          \"dmxRange\": [142, 159],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color zoom ramp in\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [163, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color zoom ramp out\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 168],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color zoom fade in\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [169, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color zoom fade out\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [172, 174],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [175, 177],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom ramp up\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [178, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom ramp down\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 219],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX1 adjust\": \"FX1 adjust n/a\"\n          }\n        }\n      ]\n    },\n    \"FX1 adjust n/a\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"FX1 adjust Trigger Delay\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"FX1 adjust Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\",\n        \"helpWanted\": \"Correct direction?\"\n      }\n    },\n    \"FX1 adjust Color offset\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"Color offset\"\n      }\n    },\n    \"FX1 adjust Amount\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"Amount\"\n      }\n    },\n    \"FX1 adjust Strength\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"Strength\"\n      }\n    },\n    \"FX2 select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Idle\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dimmer sync\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [13, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe sync\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 18],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dimmer + strobe sync\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [19, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura color sync\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [22, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura all sync\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 39],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 42],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura strobe delay\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Trigger Delay\"\n          }\n        },\n        {\n          \"dmxRange\": [43, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe alternate single\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe alternate dual\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe alternate triple\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"3-step strobe\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 60],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity random alternate\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 66],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura ramp, Beam flash\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [67, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Beam ramp, Aura flash\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 72],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity Aura, Beam ramp\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [73, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity Beam, Aura ramp\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [76, 99],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 102],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura color offset\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Color offset\"\n          }\n        },\n        {\n          \"dmxRange\": [103, 108],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [109, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hue shimmer\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Amount\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Saturation shimmer\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Amount\"\n          }\n        },\n        {\n          \"dmxRange\": [115, 126],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color strobe\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color offset strobe\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Color offset\"\n          }\n        },\n        {\n          \"dmxRange\": [133, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura color strobe\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 138],\n          \"type\": \"Effect\",\n          \"effectName\": \"Aura color offset strobe\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Color offset\"\n          }\n        },\n        {\n          \"dmxRange\": [139, 141],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color spikes\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Strength\"\n          }\n        },\n        {\n          \"dmxRange\": [142, 159],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color zoom ramp in\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [163, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color zoom ramp out\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 168],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color zoom fade in\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [169, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color zoom fade out\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [172, 174],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [175, 177],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom ramp up\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [178, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom ramp down\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 219],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\",\n          \"switchChannels\": {\n            \"FX2 adjust\": \"FX2 adjust n/a\"\n          }\n        }\n      ]\n    },\n    \"FX2 adjust n/a\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"FX2 adjust Trigger Delay\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"FX2 adjust Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\",\n        \"helpWanted\": \"Correct direction?\"\n      }\n    },\n    \"FX2 adjust Color offset\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"Color offset\"\n      }\n    },\n    \"FX2 adjust Amount\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"Amount\"\n      }\n    },\n    \"FX2 adjust Strength\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"Strength\"\n      }\n    },\n    \"FX sync\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"no sync\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"sync\"\n        },\n        {\n          \"dmxRange\": [51, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"sync shift (offset 0 to max)\"\n        },\n        {\n          \"dmxRange\": [170, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"sync random\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"no sync random\"\n        }\n      ]\n    },\n    \"Aura shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [25, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Sine wave\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [230, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Aura dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Aura color wheel effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffeb34\"],\n          \"comment\": \"LEE 790 - Moroccan Pink\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d68630\"],\n          \"comment\": \"LEE 157 - Pink\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff002c\"],\n          \"comment\": \"LEE 332 - Special rose Pink\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff3b71\"],\n          \"comment\": \"LEE 328 - Follies Pink\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8adb\"],\n          \"comment\": \"LEE 345 - Fuchsia Pink\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e2afe2\"],\n          \"comment\": \"LEE 194 - Surprise Pink\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#2801ff\"],\n          \"comment\": \"LEE 181 - Congo Blue\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"LEE 071 - Tokyo Blue\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#004eff\"],\n          \"comment\": \"LEE 120 - Deep Blue\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00c7ff\"],\n          \"comment\": \"LEE 079 - Just Blue\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffea\"],\n          \"comment\": \"LEE 132 - Medium Blue\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#95f6ff\"],\n          \"comment\": \"LEE 200 - Double CT Blue\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#89ffe3\"],\n          \"comment\": \"LEE 161 - State Blue\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d5dcde\"],\n          \"comment\": \"LEE 201 - Full CT Blue\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dbe8af\"],\n          \"comment\": \"LEE 202 - Half CT Blue\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cdffc7\"],\n          \"comment\": \"LEE 117 - Steel Blue\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#73ffa5\"],\n          \"comment\": \"LEE 353 - Lighter Blue\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#06ff8f\"],\n          \"comment\": \"LEE 118 - Light Blue\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff5e\"],\n          \"comment\": \"LEE 116 - Medium Blue Green\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#1dff00\"],\n          \"comment\": \"LEE 124 - Dark Green\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#20df00\"],\n          \"comment\": \"LEE 139 - Primary Green\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4bff00\"],\n          \"comment\": \"LEE 089 - Moss Green\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#50e800\"],\n          \"comment\": \"LEE 122 - Fern Green\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6ce200\"],\n          \"comment\": \"LEE 738 - JAS Green\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#91c200\"],\n          \"comment\": \"LEE 088 - Lime Green\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d2ff00\"],\n          \"comment\": \"LEE 100 - Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e1e800\"],\n          \"comment\": \"LEE 104 - Deep Amber\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#17d700\"],\n          \"comment\": \"LEE 179 - Chrome Orange\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f7d600\"],\n          \"comment\": \"LEE 105 - Orange\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa300\"],\n          \"comment\": \"LEE 021 - Gold Amber\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9800\"],\n          \"comment\": \"LEE 778 - Millennium Gold\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6c00\"],\n          \"comment\": \"LEE 135 - Deep Golden Amber\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff5000\"],\n          \"comment\": \"LEE 164 - Flame Red\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [180, 201],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Virtual color wheel rotation\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speed\": \"stop\",\n          \"comment\": \"Virtual color wheel rotation\"\n        },\n        {\n          \"dmxRange\": [208, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\",\n          \"comment\": \"Virtual color wheel rotation\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Aura red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Aura green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Aura blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Shutter\",\n        \"Beam dimmer\",\n        \"Zoom\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control settings\",\n        \"Beam color wheel effect\",\n        \"Beam red\",\n        \"Beam green\",\n        \"Beam blue\",\n        \"Beam white\",\n        \"Beam CTC\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"channels\": [\n        \"Shutter\",\n        \"Beam dimmer\",\n        \"Zoom\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control settings\",\n        \"Beam color wheel effect\",\n        \"Beam red\",\n        \"Beam green\",\n        \"Beam blue\",\n        \"Beam white\",\n        \"Beam CTC\",\n        \"FX1 select\",\n        \"FX1 adjust\",\n        \"FX2 select\",\n        \"FX2 adjust\",\n        \"FX sync\",\n        \"Aura shutter\",\n        \"Aura dimmer\",\n        \"Aura color wheel effect\",\n        \"Aura red\",\n        \"Aura green\",\n        \"Aura blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-axiom-hybrid.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC Axiom Hybrid\",\n  \"shortName\": \"MartinAxiomHybrid\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\", \"Ryan Goodwin\"],\n    \"createDate\": \"2017-08-07\",\n    \"lastModifyDate\": \"2026-02-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_MACAxiomHybrid_EN_D.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=TfERaCQ_WzU\",\n      \"https://www.youtube.com/watch?v=AxdUJgscNHg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [414, 630, 399],\n    \"weight\": 24.8,\n    \"power\": 600,\n    \"powerConnectors\": {\n      \"powerCON TRUE1\": \"input only\"\n    },\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"440 W short-arc discharge\",\n      \"colorTemperature\": 7000,\n      \"lumens\": 16000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [2, 44]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#71c9ed\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light green\",\n          \"colors\": [\"#8ad088\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Half CTB\",\n          \"colors\": [\"#d4f1fb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#cb6122\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#a035a0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Full CTB\",\n          \"colors\": [\"#9bd2ef\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow 2\",\n          \"colors\": [\"#f2e663\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#85d2f1\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light red\",\n          \"colors\": [\"#be2b1f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#5765b4\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark green\",\n          \"colors\": [\"#8cc783\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ac87c3\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#aa47a3\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow 1\",\n          \"colors\": [\"#ffde3f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 101\",\n          \"colors\": [\"#3b51aa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ac241b\"]\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Damped Wave\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Luck Stakes\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bite Me\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Laser Squares\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Kite Surf\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Dots in Space\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Organic Delight\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Slice It\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Circles\"\n        }\n      ]\n    },\n    \"Fixed Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"75%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"50%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"25%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"5%\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Frost\"\n        },\n        {\n          \"type\": \"AnimationGoboStart\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Not used\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"defaultValue\": 30,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 180],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"default\",\n        \"colorTemperatureEnd\": \"warm\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [10, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [19, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [37, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [55, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [72, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [73, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [81, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [82, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [91, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [99, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [100, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [109, 116],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 13,\n          \"slotNumberEnd\": 14\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 14,\n          \"slotNumberEnd\": 15\n        },\n        {\n          \"dmxRange\": [126, 126],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [127, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 15,\n          \"slotNumberEnd\": 16\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 16,\n          \"slotNumberEnd\": 17\n        },\n        {\n          \"dmxRange\": [144, 144],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [145, 152],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 0,\n          \"slotNumberEnd\": 1\n        },\n        {\n          \"dmxRange\": [153, 162],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [163, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 164],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [165, 165],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [166, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [167, 167],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [168, 168],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [169, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [170, 170],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [172, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [173, 173],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [174, 174],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [176, 176],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [177, 177],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [178, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [179, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Gobo indexing angle\": {\n      \"fineChannelAliases\": [\"Gobo indexing angle fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo rotation\": {\n      \"fineChannelAliases\": [\"Gobo rotation fine\"],\n      \"defaultValue\": 32768,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 600],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [601, 32130],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [32131, 32895],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [32896, 64515],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [64516, 65535],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"90deg\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [3, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [7, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [49, 52],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [53, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [57, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 68],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [69, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo rotation\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"25deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 228],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [229, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation fine\": \"Gobo indexing angle fine\"\n          }\n        }\n      ]\n    },\n    \"Fixed Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 19,\n          \"slotNumberEnd\": 20\n        },\n        {\n          \"dmxRange\": [201, 201],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 19.5,\n          \"shakeSpeed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [202, 202],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 19.5,\n          \"shakeSpeed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [203, 203],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 19.5,\n          \"shakeSpeed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [204, 220],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [221, 226],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [227, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Prism deployment\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet, between zoom and focus\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet, between zoom and focus\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet, in front of zoom\"\n        },\n        {\n          \"dmxRange\": [41, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet, in front of zoom\"\n        }\n      ]\n    },\n    \"Prism rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Prism lineator\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"BeamAngle\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Focus\": {\n      \"defaultValue\": 32768,\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Pan\": {\n      \"defaultValue\": 32768,\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": 32768,\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"260deg\"\n      }\n    },\n    \"Fixture control settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset fixture\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset head motors only\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan and tilt\"\n        },\n        {\n          \"dmxRange\": [19, 27],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan and tilt speed = fast\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan and tilt speed = smooth\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Parameter shortcuts = on\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Parameter shortcuts = off\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable focus tracking\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable focus tracking\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CMY Snap mode (default)\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CMY Fade mode\"\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp = on\"\n        },\n        {\n          \"dmxRange\": [45, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp = off\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Turn on onboard display\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Turn off onboard display\"\n        },\n        {\n          \"dmxRange\": [54, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Strobe\",\n        \"Dimmer\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo indexing angle / rotation\",\n        \"Gobo indexing angle / rotation fine\",\n        \"Fixed Gobo Wheel\",\n        \"Frost\",\n        \"Prism deployment\",\n        \"Prism rotation\",\n        \"Prism lineator\",\n        \"Zoom\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-encore-performance.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC Encore Performance\",\n  \"shortName\": \"MartinEncorePerf\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-01-16\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adn.harmanpro.com/site_elements/executables/7477_1526701894/UM_MACEncorePerformance_EN_A_original.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/mac-encore-performance-cld\",\n      \"https://www.martin.com/en/products/mac-encore-performance-wrm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=o6oVoTM3SrM\",\n      \"https://www.youtube.com/watch?v=nXhyPJOewcg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [480, 740, 452],\n    \"weight\": 31,\n    \"power\": 585,\n    \"powerConnectors\": {\n      \"powerCON TRUE1\": \"input only\"\n    },\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"White LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 48]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 101 SP\",\n          \"colors\": [\"#3355ad\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green 203 SP\",\n          \"colors\": [\"#5cbe49\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange 311 SP\",\n          \"colors\": [\"#ff973f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta 522 SP\",\n          \"colors\": [\"#c05dae\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Congo Blue 108 SP\",\n          \"colors\": [\"#233a9f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red 310 SP\",\n          \"colors\": [\"#eb3d33\"]\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"AnimationGoboStart\",\n          \"name\": \"Radial Breakup\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 30,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6000K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"CTB\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"3000K\",\n        \"colorTemperatureEnd\": \"7000K\"\n      }\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [15, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [29, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [43, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [57, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [71, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [85, 97],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [98, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [179, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random colors\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random colors\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random colors\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 89],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 209],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing Angle\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Indexing Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 232],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation Speed\",\n            \"Gobo Indexing / Rotation fine\": \"Gobo Rotation Speed fine\"\n          }\n        }\n      ]\n    },\n    \"Gobo Indexing Angle\": {\n      \"fineChannelAliases\": [\"Gobo Indexing Angle fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"-180deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Gobo Rotation Speed\": {\n      \"fineChannelAliases\": [\"Gobo Rotation Speed fine\"],\n      \"defaultValue\": 32768,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 600],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [601, 32130],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [32131, 32895],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [32896, 64515],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [64516, 65535],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"90deg\"\n        }\n      ]\n    },\n    \"Animation Wheel Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing / Rotation\": \"Animation Wheel Indexing Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Horizontal indexed position\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing / Rotation\": \"Animation Wheel Indexing Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Horizontal rotation\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing / Rotation\": \"Animation Wheel Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical rotation\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing / Rotation\": \"Animation Wheel Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical indexed position\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing / Rotation\": \"Animation Wheel Indexing Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Angled position rotation\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing / Rotation\": \"Animation Wheel Rotation Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Angled position vertical indexed\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing / Rotation\": \"Animation Wheel Indexing Angle\"\n          }\n        },\n        {\n          \"dmxRange\": [196, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Angled position horizontal indexed\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing / Rotation\": \"Animation Wheel Indexing Angle\"\n          }\n        }\n      ]\n    },\n    \"Animation Wheel Indexing Angle\": {\n      \"capability\": {\n        \"type\": \"WheelRotation\",\n        \"wheel\": \"Animation Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Animation Wheel Rotation Speed\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"angle\": \"90deg\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Iris\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Iris\",\n        \"openPercentStart\": \"open\",\n        \"openPercentEnd\": \"closed\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"48deg\",\n        \"angleEnd\": \"12deg\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Framing Blade 1 Insertion\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Framing Blade 1 Rotation\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeRotation\",\n          \"blade\": 1,\n          \"angleStart\": \"-100%\",\n          \"angleEnd\": \"0%\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeRotation\",\n          \"blade\": 1,\n          \"angle\": \"0%\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeRotation\",\n          \"blade\": 1,\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Framing Blade 2 Insertion\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Framing Blade 2 Rotation\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeRotation\",\n          \"blade\": 2,\n          \"angleStart\": \"-100%\",\n          \"angleEnd\": \"0%\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeRotation\",\n          \"blade\": 2,\n          \"angle\": \"0%\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeRotation\",\n          \"blade\": 2,\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Framing Blade 3 Insertion\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 3,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Framing Blade 3 Rotation\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeRotation\",\n          \"blade\": 3,\n          \"angleStart\": \"-100%\",\n          \"angleEnd\": \"0%\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeRotation\",\n          \"blade\": 3,\n          \"angle\": \"0%\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeRotation\",\n          \"blade\": 3,\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Framing Blade 4 Insertion\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 4,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Framing Blade 4 Rotation\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeRotation\",\n          \"blade\": 4,\n          \"angleStart\": \"-100%\",\n          \"angleEnd\": \"0%\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeRotation\",\n          \"blade\": 4,\n          \"angle\": \"0%\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeRotation\",\n          \"blade\": 4,\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Framing Blade System Rotation\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"-55deg\",\n          \"angleEnd\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeSystemRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"55deg\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"268deg\"\n      }\n    },\n    \"Fixture Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"No function (disables calibration)\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset entire fixture\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset color only\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset beam only\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset pan and tilt only\"\n        },\n        {\n          \"dmxRange\": [19, 22],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Linear dimming curve\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Square law dimming curve\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Inverse square law dimming curve\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"S-curve dimming curve\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Fast pan and tilt speed\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Smooth pan and tilt speed\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Parameter shortcuts = ON\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Parameter shortcuts = OFF\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Focus tracking = OFF\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable focus tracking at close range\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable focus tracking at medium range\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable focus tracking at long range\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Video tracking = ON\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Video tracking = OFF\"\n        },\n        {\n          \"dmxRange\": [38, 40],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Beam smoothing = ON\"\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Beam smoothing = OFF\"\n        },\n        {\n          \"dmxRange\": [43, 51],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Turn on control panel display\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Turn off control panel display\"\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Regulated fan speed, fixed light output intensity\"\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Full fan speed, regulated light output intensity\"\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Medium fan speed, regulated light output intensity\"\n        },\n        {\n          \"dmxRange\": [57, 57],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Low fan speed, regulated light output intensity\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Ultra-low fan speed, regulated li ght output intensity\"\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Hibernation mode = ON\"\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Hibernation mode = OFF\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan and tilt limits = ON\"\n        },\n        {\n          \"dmxRange\": [66, 66],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Pan and tilt limits = OFF\"\n        },\n        {\n          \"dmxRange\": [67, 67],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store current pan position as lower pan limit\"\n        },\n        {\n          \"dmxRange\": [68, 68],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store current pan position as upper pan limit –\"\n        },\n        {\n          \"dmxRange\": [69, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store current tilt position as lower tilt limit\"\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store current tilt position  as upper tilt limit\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Reset pan and tilt limits and disable pan/tilt limit functionality\"\n        },\n        {\n          \"dmxRange\": [72, 72],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Tungsten Emulation = ON\"\n        },\n        {\n          \"dmxRange\": [73, 73],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Tungsten Emulation = OFF\"\n        },\n        {\n          \"dmxRange\": [74, 74],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Alternative light source (color  temperature shift) = ON\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Alternative light source (color temperature shift) = OFF\"\n        },\n        {\n          \"dmxRange\": [76, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Enable calibration\"\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store pan and tilt calibration\"\n        },\n        {\n          \"dmxRange\": [102, 102],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store dimmer calibration\"\n        },\n        {\n          \"dmxRange\": [103, 103],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store cyan calibration\"\n        },\n        {\n          \"dmxRange\": [104, 104],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store magenta calibration\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store yellow calibration\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [107, 107],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store all CMY calibration\"\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store rotating gobo 1 current slot index calibration\"\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [111, 111],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store framing calibration\"\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store iris calibration\"\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store focus calibration\"\n        },\n        {\n          \"dmxRange\": [114, 114],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store zoom calibration\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store color wheel calibration\"\n        },\n        {\n          \"dmxRange\": [116, 116],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store animation wheel calibration\"\n        },\n        {\n          \"dmxRange\": [117, 198],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [199, 199],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset all calibrations to factory default\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"FX1 Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo X-Fade\"\n        },\n        {\n          \"dmxRange\": [2, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tick tick tick\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tick tock\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity sine wave\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity step\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity pulse\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Triple\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Up flash\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Up flash down flash\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random level\"\n        },\n        {\n          \"dmxRange\": [18, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Electric arc\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Thunderstorm atomic\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Thunderstorm\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Welding\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Animotion\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movie flicker\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cross chase\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random dimmers\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"Shakey dimmers\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Center out chase\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"Negative pulse\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Positive pulse\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rings in out\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color wave\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color step\"\n        },\n        {\n          \"dmxRange\": [42, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow wave\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow step\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow pulse\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB wave\"\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB step\"\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB pulse\"\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"CMY wave\"\n        },\n        {\n          \"dmxRange\": [57, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"CMY step\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"CMY pulse\"\n        },\n        {\n          \"dmxRange\": [59, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix to white wave\"\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix to white step\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix to white pulse\"\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random bold\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random mix step\"\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random mix pulse\"\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random subtle\"\n        },\n        {\n          \"dmxRange\": [66, 66],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red white blue wave\"\n        },\n        {\n          \"dmxRange\": [67, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red white blue step\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel full step\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel all step\"\n        },\n        {\n          \"dmxRange\": [72, 72],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel split step\"\n        },\n        {\n          \"dmxRange\": [73, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel random split step\"\n        },\n        {\n          \"dmxRange\": [74, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel shaker\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [76, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Water\"\n        },\n        {\n          \"dmxRange\": [77, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ice\"\n        },\n        {\n          \"dmxRange\": [78, 78],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hot and cold\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Warm and fuzzy\"\n        },\n        {\n          \"dmxRange\": [80, 80],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp\"\n        },\n        {\n          \"dmxRange\": [81, 81],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Step\"\n        },\n        {\n          \"dmxRange\": [82, 82],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [83, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom wave\"\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom step\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom ramp\"\n        },\n        {\n          \"dmxRange\": [86, 86],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random size wave\"\n        },\n        {\n          \"dmxRange\": [87, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random size step\"\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pin to flood\"\n        },\n        {\n          \"dmxRange\": [91, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pounce\"\n        },\n        {\n          \"dmxRange\": [92, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"Splash\"\n        },\n        {\n          \"dmxRange\": [93, 122],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"Milling around\"\n        },\n        {\n          \"dmxRange\": [124, 159],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire Gobo\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [162, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Water Gobo\"\n        },\n        {\n          \"dmxRange\": [163, 180],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 1\"\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 2\"\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 3\"\n        },\n        {\n          \"dmxRange\": [184, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 4\"\n        },\n        {\n          \"dmxRange\": [185, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 5\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 6\"\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 7\"\n        },\n        {\n          \"dmxRange\": [188, 209],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom fades\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade spin gobo zoom\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo twist\"\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"Effect\",\n          \"effectName\": \"Expand twist\"\n        },\n        {\n          \"dmxRange\": [214, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"Expand twist fade\"\n        },\n        {\n          \"dmxRange\": [215, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"FX1 Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"FX2 Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo X-Fade\"\n        },\n        {\n          \"dmxRange\": [2, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tick tick tick\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Tick tock\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity sine wave\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity step\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity pulse\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Double\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Triple\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Up flash\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"Up flash down flash\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random level\"\n        },\n        {\n          \"dmxRange\": [18, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Effect\",\n          \"effectName\": \"Electric arc\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Thunderstorm atomic\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Thunderstorm\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Welding\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Animotion\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Movie flicker\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cross chase\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random dimmers\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"Shakey dimmers\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Center out chase\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"Negative pulse\"\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Positive pulse\"\n        },\n        {\n          \"dmxRange\": [38, 38],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rings in out\"\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color wave\"\n        },\n        {\n          \"dmxRange\": [41, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color step\"\n        },\n        {\n          \"dmxRange\": [42, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow wave\"\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow step\"\n        },\n        {\n          \"dmxRange\": [52, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow pulse\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB wave\"\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB step\"\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB pulse\"\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"Effect\",\n          \"effectName\": \"CMY wave\"\n        },\n        {\n          \"dmxRange\": [57, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"CMY step\"\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"CMY pulse\"\n        },\n        {\n          \"dmxRange\": [59, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix to white wave\"\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix to white step\"\n        },\n        {\n          \"dmxRange\": [61, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix to white pulse\"\n        },\n        {\n          \"dmxRange\": [62, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random bold\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random mix step\"\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random mix pulse\"\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random subtle\"\n        },\n        {\n          \"dmxRange\": [66, 66],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red white blue wave\"\n        },\n        {\n          \"dmxRange\": [67, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red white blue step\"\n        },\n        {\n          \"dmxRange\": [68, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel full step\"\n        },\n        {\n          \"dmxRange\": [71, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel all step\"\n        },\n        {\n          \"dmxRange\": [72, 72],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel split step\"\n        },\n        {\n          \"dmxRange\": [73, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel random split step\"\n        },\n        {\n          \"dmxRange\": [74, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color wheel shaker\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire\"\n        },\n        {\n          \"dmxRange\": [76, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Water\"\n        },\n        {\n          \"dmxRange\": [77, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Ice\"\n        },\n        {\n          \"dmxRange\": [78, 78],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hot and cold\"\n        },\n        {\n          \"dmxRange\": [79, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Warm and fuzzy\"\n        },\n        {\n          \"dmxRange\": [80, 80],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp\"\n        },\n        {\n          \"dmxRange\": [81, 81],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Step\"\n        },\n        {\n          \"dmxRange\": [82, 82],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [83, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom wave\"\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom step\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom ramp\"\n        },\n        {\n          \"dmxRange\": [86, 86],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random size wave\"\n        },\n        {\n          \"dmxRange\": [87, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random size step\"\n        },\n        {\n          \"dmxRange\": [88, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pin to flood\"\n        },\n        {\n          \"dmxRange\": [91, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pounce\"\n        },\n        {\n          \"dmxRange\": [92, 92],\n          \"type\": \"Effect\",\n          \"effectName\": \"Splash\"\n        },\n        {\n          \"dmxRange\": [93, 122],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [123, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"Milling around\"\n        },\n        {\n          \"dmxRange\": [124, 159],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fire Gobo\"\n        },\n        {\n          \"dmxRange\": [161, 161],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [162, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Water Gobo\"\n        },\n        {\n          \"dmxRange\": [163, 180],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [181, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 1\"\n        },\n        {\n          \"dmxRange\": [182, 182],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 2\"\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 3\"\n        },\n        {\n          \"dmxRange\": [184, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 4\"\n        },\n        {\n          \"dmxRange\": [185, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 5\"\n        },\n        {\n          \"dmxRange\": [186, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 6\"\n        },\n        {\n          \"dmxRange\": [187, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Select fixed gobo 7\"\n        },\n        {\n          \"dmxRange\": [188, 209],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zoom fades\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade spin gobo zoom\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"Effect\",\n          \"effectName\": \"Gobo twist\"\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"Effect\",\n          \"effectName\": \"Expand twist\"\n        },\n        {\n          \"dmxRange\": [214, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"Expand twist fade\"\n        },\n        {\n          \"dmxRange\": [215, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"FX2 Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"FX Synchronization\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 10°\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 20°\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 30°\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 40°\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 50°\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 60°\"\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 70°\"\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 80°\"\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 90°\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 100°\"\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 110°\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 120°\"\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 130°\"\n        },\n        {\n          \"dmxRange\": [14, 14],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 140°\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 150°\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 160°\"\n        },\n        {\n          \"dmxRange\": [17, 17],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 170°\"\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 180°\"\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 190°\"\n        },\n        {\n          \"dmxRange\": [20, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 200°\"\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 210°\"\n        },\n        {\n          \"dmxRange\": [22, 22],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 220°\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 230°\"\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 240°\"\n        },\n        {\n          \"dmxRange\": [25, 25],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 250°\"\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 260°\"\n        },\n        {\n          \"dmxRange\": [27, 27],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 270°\"\n        },\n        {\n          \"dmxRange\": [28, 28],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 280°\"\n        },\n        {\n          \"dmxRange\": [29, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 290°\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 300°\"\n        },\n        {\n          \"dmxRange\": [31, 31],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 310°\"\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 320°\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 330°\"\n        },\n        {\n          \"dmxRange\": [34, 34],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 340°\"\n        },\n        {\n          \"dmxRange\": [35, 35],\n          \"type\": \"Generic\",\n          \"comment\": \"Offset shift 350°\"\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"Generic\",\n          \"comment\": \"Synchronized\"\n        },\n        {\n          \"dmxRange\": [37, 100],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"Generic\",\n          \"comment\": \"Random start (FX1 controls overall speed)\"\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"Generic\",\n          \"comment\": \"Random duration\"\n        },\n        {\n          \"dmxRange\": [141, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CLD\",\n      \"physical\": {\n        \"bulb\": {\n          \"colorTemperature\": 3000,\n          \"lumens\": 11600\n        }\n      },\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Indexing / Rotation\",\n        \"Gobo Indexing / Rotation fine\",\n        \"Animation Wheel Function\",\n        \"Animation Wheel Indexing / Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Framing Blade 1 Insertion\",\n        \"Framing Blade 1 Rotation\",\n        \"Framing Blade 2 Insertion\",\n        \"Framing Blade 2 Rotation\",\n        \"Framing Blade 3 Insertion\",\n        \"Framing Blade 3 Rotation\",\n        \"Framing Blade 4 Insertion\",\n        \"Framing Blade 4 Rotation\",\n        \"Framing Blade System Rotation\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture Control\",\n        \"FX1 Selection\",\n        \"FX1 Speed\",\n        \"FX2 Selection\",\n        \"FX2 Speed\",\n        \"FX Synchronization\"\n      ]\n    },\n    {\n      \"name\": \"WRM\",\n      \"physical\": {\n        \"bulb\": {\n          \"colorTemperature\": 6000,\n          \"lumens\": 9200\n        }\n      },\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTB\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Indexing / Rotation\",\n        \"Gobo Indexing / Rotation fine\",\n        \"Animation Wheel Function\",\n        \"Animation Wheel Indexing / Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Framing Blade 1 Insertion\",\n        \"Framing Blade 1 Rotation\",\n        \"Framing Blade 2 Insertion\",\n        \"Framing Blade 2 Rotation\",\n        \"Framing Blade 3 Insertion\",\n        \"Framing Blade 3 Rotation\",\n        \"Framing Blade 4 Insertion\",\n        \"Framing Blade 4 Rotation\",\n        \"Framing Blade System Rotation\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture Control\",\n        \"FX1 Selection\",\n        \"FX1 Speed\",\n        \"FX2 Selection\",\n        \"FX2 Speed\",\n        \"FX Synchronization\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-viper-airfx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC Viper AirFX\",\n  \"shortName\": \"MartinViperAirFX\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-08-03\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"comment\": \"Viper Air FX:\\n- 35000 Lumens \\n- 1:5 zoom - Continuous and fast zoom with auto-linked focus\\n- 160 mm precision PC front lens for fat beam looks\\n- The Martin Quadray Module is available as an accessory for the MAC Viper AirFX. It splits the MAC Viper AirFX beam into four individually controllable rays.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_MACViperAirFX_EN_B.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ECt0uykBXWI\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 44,\n    \"softwareVersion\": \"1.2.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [473, 749, 566],\n    \"weight\": 35.7,\n    \"power\": 1225,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"1000 W short-arc discharge\",\n      \"colorTemperature\": 6000,\n      \"lumens\": 35000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [11, 58]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1\", \"2\"],\n        [\"3\", \"4\"]\n      ]\n    ]\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    },\n    \"Aerial Effects Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe / Shutter\": {\n      \"defaultValue\": 30,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Lamp switches to 800 watt mode after shutter is closed for 10 seconds\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Dimmer fade\": {\n      \"fineChannelAliases\": [\"Dimmer fade fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6000K\",\n        \"colorTemperatureEnd\": \"3200K\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [201, 203],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [204, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Aerial effects wheel: gobo indexing\": {\n      \"fineChannelAliases\": [\"Aerial effects wheel: gobo indexing fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Aerial Effects Wheel\",\n        \"angleStart\": \"-197.5deg\",\n        \"angleEnd\": \"197.5deg\"\n      }\n    },\n    \"Aerial effects wheel: gobo rotation\": {\n      \"fineChannelAliases\": [\"Aerial effects wheel: gobo rotation fine\"],\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 600],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [601, 32130],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [32131, 32895],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [32896, 64515],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [64516, 65535],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"angle\": \"90deg\"\n        }\n      ]\n    },\n    \"Aerial effects wheel: gobo selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 2,\n          \"comment\": \"Indexed\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 3,\n          \"comment\": \"Indexed\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 4,\n          \"comment\": \"Indexed\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 5,\n          \"comment\": \"Indexed\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 6,\n          \"comment\": \"Indexed\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 2,\n          \"comment\": \"Continuous Rotation\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo rotation\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 3,\n          \"comment\": \"Continuous Rotation\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo rotation\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 4,\n          \"comment\": \"Continuous Rotation\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo rotation\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 5,\n          \"comment\": \"Continuous Rotation\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo rotation\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 6,\n          \"comment\": \"Continuous Rotation\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo rotation\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 89],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 119],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 149],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 179],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 209],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"shakeAngleStart\": \"360deg\",\n          \"shakeAngleEnd\": \"10deg\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo indexing\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 232],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo rotation\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Aerial Effects Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Aerial effects wheel: gobo indexing / rotation\": \"Aerial effects wheel: gobo rotation\",\n            \"Aerial effects wheel: gobo indexing / rotation fine\": \"Aerial effects wheel: gobo rotation fine\"\n          }\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [201, 203],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [204, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Wash effect\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Wash\",\n        \"parameterStart\": \"off\",\n        \"parameterEnd\": \"high\"\n      }\n    },\n    \"Iris\": {\n      \"capability\": {\n        \"type\": \"Iris\",\n        \"openPercentStart\": \"open\",\n        \"openPercentEnd\": \"closed\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Pan\": {\n      \"defaultValue\": 32768,\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": 32768,\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"268deg\"\n      }\n    },\n    \"Fixture control / settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"No function (disables calibration)\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset entire fixture\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset dimmer and shutter only\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset color (CMY, CTO and color wheel) only\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset beam (aerial effect gobos, static gobos, iris, wash effect, zoom, focus) only\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset pan and tilt only\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Lamp off\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Enable calibration\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Linear dimming curve (menu override, setting unaffected by power off/on)\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Square law dimming curve (menu override, factory default setting, setting unaffected by power off/on)\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Inverse square law dimming curve (menu override, setting unaffected by power off/on)\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"S-curve dimming curv (menu override, setting unaffected by power off/on)\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Normal pan and tilt speed (menu override - setting returns to MENU setting after power on/off)\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Fast pan and tilt speed (default setting, menu override - setting returns to MENU setting after power on/off)\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Slow pan and tilt speed (menu override - setting returns to MENU setting after power on/off)\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Effect shortcuts = ON (default setting, menu override, setting stays at factory default ON at power off/on)\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Effect shortcuts = OFF (menu override, setting returns to factory default ON at power off/on)\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Disable zoom/focus linkin\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable zoom/focus linking, near distance\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable zoom/focus linking, medium distance (default setting)\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable zoom/focus linking, far distance\"\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output full, set to 100% (default setting)\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output reduced to 90%\"\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output reduced to 80%\"\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output reduced to 70%\"\n        },\n        {\n          \"dmxRange\": [133, 134],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output reduced to 60%\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Auto blackout = ON\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Auto blackout = OFF (default setting)\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Turn on control panel display\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Turn off control panel display\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store pan and tilt calibration\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store dimmer calibration\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store cyan calibration\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store magenta calibration\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store yellow calibration\"\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store CTC calibration\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store all CMY and CTC calibration\"\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store aerial effect gobo wheel (wheel 1) slot index calibration\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store beamshaper accessory calibration (if fitted)\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store iris calibration\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store focus calibration\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store zoom calibration\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store pan calibration\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store tilt calibration\"\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset all calibration values to factory defaults\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Reserved for future use 1\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved for future use 2\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved for future use 3\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved for future use 4\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved for future use 5\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Quadray control\": {\n      \"defaultValue\": 101,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Indexing\",\n          \"switchChannels\": {\n            \"Quadray 1\": \"Ray 1 Indexing\",\n            \"Quadray 2\": \"Ray 2 Indexing\",\n            \"Quadray 3\": \"Ray 3 Indexing\",\n            \"Quadray 4\": \"Ray 4 Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rotation\",\n          \"switchChannels\": {\n            \"Quadray 1\": \"Ray 1 Rotation\",\n            \"Quadray 2\": \"Ray 2 Rotation\",\n            \"Quadray 3\": \"Ray 3 Rotation\",\n            \"Quadray 4\": \"Ray 4 Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Quadray 1\": \"Ray 1 n/a\",\n            \"Quadray 2\": \"Ray 2 n/a\",\n            \"Quadray 3\": \"Ray 3 n/a\",\n            \"Quadray 4\": \"Ray 4 n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Positions\",\n          \"switchChannels\": {\n            \"Quadray 1\": \"FX fade time\",\n            \"Quadray 2\": \"Ray 2 n/a\",\n            \"Quadray 3\": \"Ray 3 n/a\",\n            \"Quadray 4\": \"Ray 4 n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Continuous FX\",\n          \"switchChannels\": {\n            \"Quadray 1\": \"FX rotation\",\n            \"Quadray 2\": \"FX start times\",\n            \"Quadray 3\": \"Ray 3 n/a\",\n            \"Quadray 4\": \"Ray 4 n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static FX\",\n          \"switchChannels\": {\n            \"Quadray 1\": \"Static FX amount\",\n            \"Quadray 2\": \"Ray 2 n/a\",\n            \"Quadray 3\": \"Ray 3 n/a\",\n            \"Quadray 4\": \"Ray 4 n/a\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 255],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\",\n          \"switchChannels\": {\n            \"Quadray 1\": \"Ray 1 n/a\",\n            \"Quadray 2\": \"Ray 2 n/a\",\n            \"Quadray 3\": \"Ray 3 n/a\",\n            \"Quadray 4\": \"Ray 4 n/a\"\n          }\n        }\n      ]\n    },\n    \"FX fade time\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"0s\",\n        \"durationEnd\": \"10s\"\n      }\n    },\n    \"FX rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"FX start times\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Synchronized (all fixtures start FX immediately)\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Random (0-6s random offset between fixtures)\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Static FX amount\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"low\",\n        \"parameterEnd\": \"high\",\n        \"comment\": \"Amount\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Ray $pixelKey Indexing\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Ray $pixelKey Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Ray $pixelKey n/a\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic\",\n      \"shortName\": \"basic\",\n      \"channels\": [\n        \"Strobe / Shutter\",\n        \"Dimmer fade\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Aerial effects wheel: gobo selection\",\n        \"Aerial effects wheel: gobo indexing / rotation\",\n        \"Aerial effects wheel: gobo indexing / rotation fine\",\n        \"Static Gobo Wheel\",\n        \"Wash effect\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control / settings\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Strobe / Shutter\",\n        \"Dimmer fade\",\n        \"Dimmer fade fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Aerial effects wheel: gobo selection\",\n        \"Aerial effects wheel: gobo indexing / rotation\",\n        \"Aerial effects wheel: gobo indexing / rotation fine\",\n        \"Static Gobo Wheel\",\n        \"Wash effect\",\n        \"Iris\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control / settings\",\n        \"Reserved for future use 1\",\n        \"Reserved for future use 2\",\n        \"Reserved for future use 3\",\n        \"Reserved for future use 4\",\n        \"Reserved for future use 5\",\n        \"Quadray control\",\n        \"Quadray 1\",\n        \"Quadray 2\",\n        \"Quadray 3\",\n        \"Quadray 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-viper-performance.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC Viper Performance\",\n  \"shortName\": \"MartinViperPerf\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-09-08\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/35000275c%20UM_MACViperPerf_EN_C.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=KfvX_vPbLc0\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 65,\n    \"softwareVersion\": \"1.0.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [472, 748, 566],\n    \"weight\": 37.9,\n    \"power\": 1225,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"1000 W short-arc discharge\",\n      \"colorTemperature\": 6000,\n      \"lumens\": 26000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 44]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#3857ad\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#61c15a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#fb9955\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Rose\",\n          \"colors\": [\"#fbe7f1\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#da9ecc\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep Blue\",\n          \"colors\": [\"#994ba6\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#de4b48\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"AnimationGoboStart\",\n          \"name\": \"Ripple Waves\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe / Shutter\": {\n      \"defaultValue\": 30,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"800W mode after 10s\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Dimmer fade\": {\n      \"fineChannelAliases\": [\"Dimmer fade fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6000K\",\n        \"colorTemperatureEnd\": \"3200K\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [182, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"continuous rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo rotation speed\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo rotation speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"continuous rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo rotation speed\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo rotation speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"continuous rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo rotation speed\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo rotation speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"continuous rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo rotation speed\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo rotation speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"continuous rotation\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo rotation speed\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo rotation speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 89],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 209],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo indexing angle\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo indexing angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 232],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo rotation speed\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo rotation speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo indexing angle / rotation speed\": \"Gobo rotation speed\",\n            \"Gobo indexing angle / rotation speed fine\": \"Gobo rotation speed fine\"\n          }\n        }\n      ]\n    },\n    \"Gobo indexing angle\": {\n      \"fineChannelAliases\": [\"Gobo indexing angle fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Gobo Wheel\",\n        \"angleStart\": \"-197.5deg\",\n        \"angleEnd\": \"197.5deg\"\n      }\n    },\n    \"Gobo rotation speed\": {\n      \"fineChannelAliases\": [\"Gobo rotation speed fine\"],\n      \"defaultValue\": 32768,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 600],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [601, 32130],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [32131, 32895],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [32896, 64515],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [64516, 65535],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angle\": \"90deg\"\n        }\n      ]\n    },\n    \"Animation Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Generic\",\n          \"comment\": \"Indexed\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Generic\",\n          \"comment\": \"Continuous rotation\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"WheelRotation\",\n          \"angle\": \"0deg\",\n          \"comment\": \"Position 1\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"WheelRotation\",\n          \"angle\": \"-7deg\",\n          \"comment\": \"Position 2\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"WheelRotation\",\n          \"angle\": \"-14deg\",\n          \"comment\": \"Position 3\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"WheelRotation\",\n          \"angle\": \"-21deg\",\n          \"comment\": \"Position 4\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"WheelRotation\",\n          \"angle\": \"-28deg\",\n          \"comment\": \"Position 5\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"WheelRotation\",\n          \"angle\": \"-35deg\",\n          \"comment\": \"Position 6\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"WheelRotation\",\n          \"angle\": \"-42deg\",\n          \"comment\": \"Position 7\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\",\n          \"switchChannels\": {\n            \"Animation Wheel Indexing/Rotation\": \"Animation Wheel Rotation\"\n          }\n        }\n      ]\n    },\n    \"Animation Wheel Indexing\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"WheelRotation\",\n        \"wheel\": \"Animation Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Animation Wheel Rotation\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Animation Wheel\",\n          \"angle\": \"90deg\"\n        }\n      ]\n    },\n    \"Framing blade 1, position\": {\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\",\n        \"blade\": 1\n      }\n    },\n    \"Framing blade 1, angle\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeRotation\",\n          \"angleStart\": \"-30deg\",\n          \"angleEnd\": \"0deg\",\n          \"blade\": 1\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeRotation\",\n          \"angle\": \"0deg\",\n          \"blade\": 1\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"30deg\",\n          \"blade\": 1\n        }\n      ]\n    },\n    \"Framing blade 2, position\": {\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\",\n        \"blade\": 2\n      }\n    },\n    \"Framing blade 2, angle\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeRotation\",\n          \"angleStart\": \"-30deg\",\n          \"angleEnd\": \"0deg\",\n          \"blade\": 2\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeRotation\",\n          \"angle\": \"0deg\",\n          \"blade\": 2\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"30deg\",\n          \"blade\": 2\n        }\n      ]\n    },\n    \"Framing blade 3, position\": {\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\",\n        \"blade\": 3\n      }\n    },\n    \"Framing blade 3, angle\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeRotation\",\n          \"angleStart\": \"-30deg\",\n          \"angleEnd\": \"0deg\",\n          \"blade\": 3\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeRotation\",\n          \"angle\": \"0deg\",\n          \"blade\": 3\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"30deg\",\n          \"blade\": 3\n        }\n      ]\n    },\n    \"Framing blade 4, position\": {\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\",\n        \"blade\": 4\n      }\n    },\n    \"Framing blade 4, angle\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeRotation\",\n          \"angleStart\": \"-30deg\",\n          \"angleEnd\": \"0deg\",\n          \"blade\": 4\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeRotation\",\n          \"angle\": \"0deg\",\n          \"blade\": 4\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"30deg\",\n          \"blade\": 4\n        }\n      ]\n    },\n    \"Framing indexing angle\": {\n      \"defaultValue\": 127,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"-55deg\",\n          \"angleEnd\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"BladeSystemRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"55deg\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism indexing/rotation\": \"Prism indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 138],\n          \"type\": \"Prism\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Prism indexing/rotation\": \"Prism indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [139, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Prism indexing/rotation\": \"Prism rotation\"\n          }\n        }\n      ]\n    },\n    \"Prism indexing\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 126],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"-100%\",\n          \"angleEnd\": \"-1%\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"1%\",\n          \"angleEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Prism rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"45deg\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"capability\": {\n        \"type\": \"Iris\",\n        \"openPercentStart\": \"open\",\n        \"openPercentEnd\": \"closed\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"44deg\",\n        \"angleEnd\": \"10deg\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"268deg\"\n      }\n    },\n    \"Fixture control/settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset entire fixture\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset dimmer and shutter only\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset CMY, CTO and color wheel only\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset effects (gobo and animation wheels, iris, prism, frost, zoom, focus)\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset pan and tilt only\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset framing\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp on\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"enable calibration\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"linear dimming curve\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"square law dimming curve\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"inverse square lae dimming curve\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"s-curve dimming curve\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"normal pan and tilt speed\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"fast pan and tilt speed\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"slow pan and tilt speed\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"effect shortcuts = on\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"effect shortcuts = off\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"disable zoom/focus linking\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"enable zoom/focus linking, near distance\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"enable zoom/focus linking, medium distance (default)\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"enable zoom/focus linking, far distance\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ballast output full, set to 100% (default)\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ballast output reduced to 90%\"\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ballast output reduced to 80%\"\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ballast output reduced to 70%\"\n        },\n        {\n          \"dmxRange\": [133, 134],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ballast output reduced to 60%\"\n        },\n        {\n          \"dmxRange\": [135, 144],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"auto blackout = on\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"auto blackout = off (default)\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"turn on display\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"turn off display\",\n          \"hold\": \"1s\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store pan and tilt calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store dimmer calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store cyan calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store magenta calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store yellow calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store CTC calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store all CMY and CTC calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store gobo wheel current slot index calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [205, 214],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store prism calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store iris calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store focus calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store zoom calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store pan calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"store tilt calibration\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset all calibration values to factory defaults\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Reserved1\": {\n      \"name\": \"Reserved for future use\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved2\": {\n      \"name\": \"Reserved for future use\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved3\": {\n      \"name\": \"Reserved for future use\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved4\": {\n      \"name\": \"Reserved for future use\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved5\": {\n      \"name\": \"Reserved for future use\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic 16-bit\",\n      \"shortName\": \"bas\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Strobe / Shutter\",\n        \"Dimmer fade\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo indexing angle / rotation speed\",\n        \"Gobo indexing angle / rotation speed fine\",\n        \"Animation Wheel\",\n        \"Animation Wheel Indexing/Rotation\",\n        \"Framing blade 1, position\",\n        \"Framing blade 1, angle\",\n        \"Framing blade 2, position\",\n        \"Framing blade 2, angle\",\n        \"Framing blade 3, position\",\n        \"Framing blade 3, angle\",\n        \"Framing blade 4, position\",\n        \"Framing blade 4, angle\",\n        \"Framing indexing angle\",\n        \"Frost\",\n        \"Prism\",\n        \"Prism indexing/rotation\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control/settings\"\n      ]\n    },\n    {\n      \"name\": \"Extended 16-bit\",\n      \"shortName\": \"ext\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Strobe / Shutter\",\n        \"Dimmer fade\",\n        \"Dimmer fade fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo indexing angle / rotation speed\",\n        \"Gobo indexing angle / rotation speed fine\",\n        \"Animation Wheel\",\n        \"Animation Wheel Indexing/Rotation\",\n        \"Framing blade 1, position\",\n        \"Framing blade 1, angle\",\n        \"Framing blade 2, position\",\n        \"Framing blade 2, angle\",\n        \"Framing blade 3, position\",\n        \"Framing blade 3, angle\",\n        \"Framing blade 4, position\",\n        \"Framing blade 4, angle\",\n        \"Framing indexing angle\",\n        \"Frost\",\n        \"Prism\",\n        \"Prism indexing/rotation\",\n        \"Iris\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control/settings\",\n        \"Reserved1\",\n        \"Reserved2\",\n        \"Reserved3\",\n        \"Reserved4\",\n        \"Reserved5\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mac-viper-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MAC Viper Wash (DX)\",\n  \"shortName\": \"MartinViperWash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-09-11\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"comment\": \"This fixture definition covers both the MAC Viper Wash and the MAC Viper Wash DX. The Color Wheel, Iris and all Internal Barndoor channels are only available in the DX variant.\\n\\nNote: Focus and Zoom are 8-bit channels, the manual is wrong there.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_MACViperWash_EN_B.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=K5KV7ngATCU\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 43,\n    \"softwareVersion\": \"1.3.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [473, 749, 566],\n    \"weight\": 33,\n    \"power\": 1225,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"1000 W short-arc discharge\",\n      \"colorTemperature\": 6000,\n      \"lumens\": 33000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13.5, 59]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe / Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Lamp switches to 800 watt mode after shutter is closed for 10 seconds\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6000K\",\n        \"colorTemperatureEnd\": \"3200K\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [201, 203],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [204, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"capability\": {\n        \"type\": \"Iris\",\n        \"openPercentStart\": \"open\",\n        \"openPercentEnd\": \"closed\"\n      }\n    },\n    \"Internal barndoor 1\": {\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Internal barndoor 2\": {\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Internal barndoors rotation\": {\n      \"defaultValue\": 100,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"-10deg\",\n          \"angleEnd\": \"-1deg\"\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"BladeSystemRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [11, 99],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"1deg\",\n          \"angleEnd\": \"89deg\"\n        },\n        {\n          \"dmxRange\": [100, 100],\n          \"type\": \"BladeSystemRotation\",\n          \"angle\": \"90deg\"\n        },\n        {\n          \"dmxRange\": [101, 189],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"91deg\",\n          \"angleEnd\": \"179deg\"\n        },\n        {\n          \"dmxRange\": [190, 190],\n          \"type\": \"BladeSystemRotation\",\n          \"angle\": \"180deg\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"181deg\",\n          \"angleEnd\": \"190deg\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"268deg\"\n      }\n    },\n    \"Fixture control / settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"No function (disables calibration)\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset entire fixture\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset dimmer and shutter only\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset color (CMY and CTO plus color wheel if fitted) only\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset beam (zoom, focus plus iris if fitted) only\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset pan and tilt only\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Lamp off\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Enable calibration\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Linear dimming curve (menu override, setting unaffected by power off/on)\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Square law dimming curve (menu override, factory default setting, setting unaffected by power off/on)\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Inverse square law dimming curve (menu override, setting unaffected by power off/on)\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"S-curve dimming curve (menu override, setting unaffected by power off/on)\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Normal pan and tilt speed (menu override - setting returns to MENU setting after power on/off)\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Fast pan and tilt speed (default setting, menu override - setting returns to MENU setting after power on/off)\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Slow pan and tilt speed (menu override - setting returns to MENU setting after power on/off)\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Effect shortcuts = ON (default setting, menu override, setting stays at factory default ON at power off/on)\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Effect shortcuts = OFF (menu override, setting returns to factory default ON at power off/on)\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Disable zoom/focus linkin\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable zoom/focus linking, near distance\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable zoom/focus linking, medium distance (default setting)\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Enable zoom/focus linking, far distance\"\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output full, set to 100% (default setting)\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output reduced to 90%\"\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output reduced to 80%\"\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output reduced to 70%\"\n        },\n        {\n          \"dmxRange\": [133, 134],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Ballast output reduced to 60%\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Auto blackout = ON\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Auto blackout = OFF (default setting)\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Turn on control panel display\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"hold\": \"1s\",\n          \"comment\": \"Turn off control panel display\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store pan and tilt calibration\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store dimmer calibration\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store cyan calibration\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store magenta calibration\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store yellow calibration\"\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store CTC calibration\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store all CMY and CTC calibration\"\n        },\n        {\n          \"dmxRange\": [200, 214],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store internal barndoors calibration\"\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store iris calibration\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store focus calibration\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store zoom calibration\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store pan calibration\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Store tilt calibration\"\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset all calibration values to factory defaults\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Reserved for future use 1\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved for future use 2\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved for future use 3\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved for future use 4\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Reserved for future use 5\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic\",\n      \"shortName\": \"basic\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Strobe / Shutter\",\n        \"Dimmer\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Iris\",\n        \"Internal barndoor 1\",\n        \"Internal barndoor 2\",\n        \"Internal barndoors rotation\",\n        \"Zoom\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control / settings\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"ext\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Strobe / Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO\",\n        \"Color Wheel\",\n        \"Iris\",\n        \"Internal barndoor 1\",\n        \"Internal barndoor 2\",\n        \"Internal barndoors rotation\",\n        \"Zoom\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture control / settings\",\n        \"Reserved for future use 1\",\n        \"Reserved for future use 2\",\n        \"Reserved for future use 3\",\n        \"Reserved for future use 4\",\n        \"Reserved for future use 5\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/magnum-2500-hz.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Magnum 2500 HZ\",\n  \"shortName\": \"MartinMagnum2.5k\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-08-08\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_Magnum2500Hz_EN_F.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wCQePza8akg\",\n      \"https://www.youtube.com/watch?v=Nc0ku6yCe4w\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [285, 286, 455],\n    \"weight\": 15.7,\n    \"power\": 920,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 29],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [30, 255],\n          \"type\": \"Fog\",\n          \"fogOutputStart\": \"0m^3/min\",\n          \"fogOutputEnd\": \"2500m^3/min\",\n          \"fogType\": \"Haze\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Fog\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mania-scx500.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mania SCX500\",\n  \"shortName\": \"SCX500\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Michael Stiller\", \"Ryan Goodwin\", \"Ken Harris\"],\n    \"createDate\": \"2019-01-14\",\n    \"lastModifyDate\": \"2023-10-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/786449/Martin-Mania-Scx500.html\",\n      \"https://adn.harmanpro.com/site_elements/executables/5792_1526694868/UM_ManiaSCX500_EN_C_original.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en-US/products/mania-scx500\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=0Vl3DwUR9Xo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [445, 178, 204],\n    \"weight\": 6.7,\n    \"power\": 164,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"H5 MR16 halogen\",\n      \"colorTemperature\": 4000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue B04\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange B09\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red B01\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Yellow B03\",\n          \"colors\": [\"#ffff99\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink B12\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Medium Blue B13\",\n          \"colors\": [\"#0000cd\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Red B19\",\n          \"colors\": [\"#ff7f7f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green B08\",\n          \"colors\": [\"#90ee90\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue B05\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink B11\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue B06\",\n          \"colors\": [\"#add8e6\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow B02\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Primary Red B14\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green B07\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Mix 1\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Mix 2\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Mix 3\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Mix 4\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Mix 5\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Dune\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Sunburst\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gemini\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Mr. Spok\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Triptych\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Space lice\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Nova\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Circular saw\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Racer\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Black hole\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bat\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Beep\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Fame\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Thatch\"\n        },\n        {\n          \"type\": \"Closed\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 68],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [69, 100],\n          \"type\": \"Generic\",\n          \"comment\": \"Remote stand-alone, auto trig\"\n        },\n        {\n          \"dmxRange\": [101, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [113, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [125, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [137, 148],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [149, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [161, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [173, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [185, 196],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [197, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [209, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [221, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [233, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"5s\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [12, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [24, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [36, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [42, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [48, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [54, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [60, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [66, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [72, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [78, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [84, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [90, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [102, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [108, 113],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [114, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10.5\n        },\n        {\n          \"dmxRange\": [120, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [126, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11.5\n        },\n        {\n          \"dmxRange\": [132, 137],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [138, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12.5\n        },\n        {\n          \"dmxRange\": [144, 149],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [150, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13.5\n        },\n        {\n          \"dmxRange\": [156, 161],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [162, 167],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14.5\n        },\n        {\n          \"dmxRange\": [168, 173],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [174, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [180, 185],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [186, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [192, 197],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 19\n        },\n        {\n          \"dmxRange\": [198, 203],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 20\n        },\n        {\n          \"dmxRange\": [204, 229],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [96, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [108, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [120, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [132, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [144, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [156, 167],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [168, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"72deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Tracking (default)\"\n        },\n        {\n          \"dmxRange\": [2, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Color/Gobo Wheel Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Tracking (default)\"\n        },\n        {\n          \"dmxRange\": [2, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"0Hz\",\n          \"comment\": \"Change speed from one color/gobo to the next one\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Effects\",\n        \"Intensity\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Pan\",\n        \"Tilt\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Effects\",\n        \"Intensity\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Color/Gobo Wheel Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/mx-10-extreme.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MX-10 Extreme\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-03-15\",\n    \"lastModifyDate\": \"2024-01-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/en/site_elements/user-manual-a456d8e8-ed18-4ca8-8c6e-be905dc53b83\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/mx-10-extreme\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [340, 315, 735],\n    \"weight\": 22,\n    \"power\": 360,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"Philips MSD 250/2 (250W discharge lamp)\",\n      \"colorTemperature\": 8500,\n      \"lumens\": 3757\n    },\n    \"lens\": {\n      \"degreesMinMax\": [18, 18]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Eclipse\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Shark bar\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Phat fan\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Tail spin\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Sun\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Triangle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Oriental fire\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Paint mix\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"direction\": \"CW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTC\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow 603\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 104\",\n          \"colors\": [\"#5badff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink 312\",\n          \"colors\": [\"#ff80ca\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green 206\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 108\",\n          \"colors\": [\"#0000aa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red 301\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta 507\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue 101\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange 306\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark green\",\n          \"colors\": [\"#1dff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple 502\",\n          \"colors\": [\"#9200ff\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 72],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [73, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Opening pulse\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Closing pulse\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 147],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [148, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"50%\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [168, 187],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [188, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [191, 193],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true,\n          \"comment\": \"Opening pulse\"\n        },\n        {\n          \"dmxRange\": [194, 196],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true,\n          \"comment\": \"Opening pulse\"\n        },\n        {\n          \"dmxRange\": [197, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speed\": \"fast\",\n          \"randomTiming\": true,\n          \"comment\": \"Closing pulse\"\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speed\": \"slow\",\n          \"randomTiming\": true,\n          \"comment\": \"Closing pulse\"\n        },\n        {\n          \"dmxRange\": [203, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [208, 217],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset; if this command is disabled in the menu, it can be executed only if the CTC filter, prism with no rotation, and open gobo are selected\"\n        },\n        {\n          \"dmxRange\": [218, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [228, 237],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [238, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Lamp off; if this command is disabled in the menu, it can be executed only if the CTC filter, prism with no rotation, and open gobo are selected\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [13, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [24, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [25, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [36, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [37, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [49, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [61, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [72, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [73, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [84, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [85, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [97, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [108, 108],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [109, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [121, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [132, 132],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [133, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [144, 144],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [145, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 13,\n          \"slotNumberEnd\": 14\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [208, 226],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [227, 245],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"WheelShake\",\n          \"isShaking\": \"wheel\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"WheelShake\",\n          \"isShaking\": \"wheel\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 134],\n          \"type\": \"WheelShake\",\n          \"isShaking\": \"wheel\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [135, 149],\n          \"type\": \"WheelShake\",\n          \"isShaking\": \"wheel\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"WheelShake\",\n          \"isShaking\": \"wheel\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [165, 179],\n          \"type\": \"WheelShake\",\n          \"isShaking\": \"wheel\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 194],\n          \"type\": \"WheelShake\",\n          \"isShaking\": \"wheel\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [195, 209],\n          \"type\": \"WheelShake\",\n          \"isShaking\": \"wheel\",\n          \"slotNumber\": 1,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 232],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        }\n      ]\n    },\n    \"Gobo Indexing\": {\n      \"capability\": {\n        \"type\": \"WheelRotation\",\n        \"wheel\": \"Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"395deg\"\n      }\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [3, 127],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 253],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"20m\",\n        \"distanceEnd\": \"2m\"\n      }\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 79],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [90, 149],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [150, 215],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 1\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 2\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 3\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 4\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 5\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 6\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 7\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism Macro 8\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"75deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking\"\n        },\n        {\n          \"dmxRange\": [3, 245],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Tracking, PTSP NORM (menu override)\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking, PTSP FAST (menu override)\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking mode; only for Dimmer, Focus, Color, Gobo Indexing\"\n        },\n        {\n          \"dmxRange\": [3, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Speed; only for Dimmer, Focus, Color, Gobo Indexing\",\n          \"parameterStart\": \"fast\",\n          \"parameterEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [246, 248],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking/Normal, SCUT OFF (menu override); only for Color, Gobo Selection\"\n        },\n        {\n          \"dmxRange\": [249, 251],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tracking/Normal, SCUT ON (menu override); only for Color, Gobo Selection\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Indexing / Rotation\",\n        \"Focus\",\n        \"Prism\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/roboscan-812.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RoboScan 812\",\n  \"shortName\": \"MartinRoboScan812\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-04-18\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_RoboScan812_EN_C.PDF\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=C2AqCvZnVes\",\n      \"https://www.youtube.com/watch?v=8l6v8Ndsyp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [190, 165, 436],\n    \"weight\": 9.4,\n    \"power\": 170,\n    \"DMXconnector\": \"3-pin (swapped +/-)\",\n    \"lens\": {\n      \"degreesMinMax\": [15.5, 15.5]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Closed\"\n        },\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ca1f7b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#90ee90\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#00008b\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Closed\"\n        },\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Dot\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Line\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Stars\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Triangles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Star\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Dots\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bells\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Cone\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Phone\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Window\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Triangle\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 74,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 74],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Gobo strobe\"\n        },\n        {\n          \"dmxRange\": [75, 138],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Color strobe\"\n        },\n        {\n          \"dmxRange\": [139, 170],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Remote Auto Trigger\"\n        },\n        {\n          \"dmxRange\": [171, 202],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [203, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset fixture\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [136, 149],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [150, 150],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [151, 164],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [165, 165],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [166, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [210, 214],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [136, 149],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [150, 150],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [151, 164],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [165, 165],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [166, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [210, 214],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        }\n      ]\n    },\n    \"Pan\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"173deg\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"83deg\"\n      }\n    },\n    \"Movement Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking mode\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Color/Gobo Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking mode\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel tracking\",\n      \"shortName\": \"tracking\",\n      \"channels\": [\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Pan\",\n        \"Tilt\"\n      ]\n    },\n    {\n      \"name\": \"7-channel vector\",\n      \"shortName\": \"vector\",\n      \"channels\": [\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Pan\",\n        \"Tilt\",\n        \"Movement Speed\",\n        \"Color/Gobo Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/rush-mh-2-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Rush MH 2 Wash\",\n  \"shortName\": \"MartinRushMH2\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-08-07\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"comment\": \"Rush MH 2 Wash:\\n- DMX, music trig and auto trig operation\\n- 17° one-tenth peak angle\\n- Extremely fast and agile\\n- Electronic dimming and strobe\\n- 3 & 5 pin XLR\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_RUSHMH2Wash_EN_G.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=hJ8CK0FpmNA\",\n      \"https://www.youtube.com/watch?v=YQTK6GbHbSg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [258, 305, 156],\n    \"weight\": 5.7,\n    \"power\": 125,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"7 x 10 W RGBW Cree MC-E LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Electronic Shutter Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [50, 64],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"burst pulse\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true,\n          \"comment\": \"burst pulse\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"sine wave\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [230, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Fixture Control Settings\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset entire fixture\"\n        },\n        {\n          \"dmxRange\": [15, 94],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable blackout during P/T movement\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during P/T movement\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fast dimming, unrestricted effects speed\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Smooth dimming, slightly reduced effects speed\"\n        },\n        {\n          \"dmxRange\": [125, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Illuminate display\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stand-alone\"\n        }\n      ]\n    },\n    \"Color Wheel Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb4a5\"],\n          \"comment\": \"LEE 790 - Moroccan pink\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff92a3\"],\n          \"comment\": \"LEE 157 - Pink\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff3787\"],\n          \"comment\": \"LEE 332 - Special rose pink\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff64c8\"],\n          \"comment\": \"LEE 328 - Follies pink\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cd6ed7\"],\n          \"comment\": \"LEE 345 - Fuchsia pink\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#be8cf0\"],\n          \"comment\": \"LEE 194 - Surprise pink\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5000aa\"],\n          \"comment\": \"LEE 181 - Congo blue\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000b4\"],\n          \"comment\": \"LEE 071 - Tokyo blue\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#005fbe\"],\n          \"comment\": \"LEE 120 - Deep blue\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#3c8cd2\"],\n          \"comment\": \"LEE 079 - Just blue\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00a0dc\"],\n          \"comment\": \"LEE 132 - Medium blue\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#91bef5\"],\n          \"comment\": \"LEE 200 - Double CT blue\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#7dd2f5\"],\n          \"comment\": \"LEE 161 - Slate blue\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c3e1fa\"],\n          \"comment\": \"LEE 201 - Full CT blue\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d7f0ff\"],\n          \"comment\": \"LEE 202 - Half CT blue\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b4faf5\"],\n          \"comment\": \"LEE 117 - Steel blue\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#61e8e3\"],\n          \"comment\": \"LEE 353 - Lighter blue\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00e1eb\"],\n          \"comment\": \"LEE 118 - Light blue\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00c8b9\"],\n          \"comment\": \"LEE 116 - Medium blue green\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00dc78\"],\n          \"comment\": \"LEE 124 - Dark green\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#4bc300\"],\n          \"comment\": \"LEE 139 - Primary green\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5adc5a\"],\n          \"comment\": \"LEE 089 - Moss green\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#78fa6e\"],\n          \"comment\": \"LEE 122 - Fern green\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aaff00\"],\n          \"comment\": \"LEE 738 - JAS green\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dcff64\"],\n          \"comment\": \"LEE 088 - Lime green\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f5ff00\"],\n          \"comment\": \"LEE 100 - Spring yellow\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffdc00\"],\n          \"comment\": \"LEE 104 - Deep amber\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbe00\"],\n          \"comment\": \"LEE 179 - Chrome orange\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa000\"],\n          \"comment\": \"LEE 105 - Orange\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff8c32\"],\n          \"comment\": \"LEE 021 - Gold amber\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7600\"],\n          \"comment\": \"LEE 778 - Millennium gold\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff5f00\"],\n          \"comment\": \"LEE 135 - Deep golden amber\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff3200\"],\n          \"comment\": \"LEE 164 - Flame red\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [180, 201],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [208, 229],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"fast\",\n          \"comment\": \"random color\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"50%\",\n          \"comment\": \"random color\"\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"slow\",\n          \"comment\": \"random color\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Electronic Shutter Effect\",\n        \"Dimmer\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Fixture Control Settings\",\n        \"Color Wheel Effect\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/rush-mh-3-beam.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Rush MH 3 Beam\",\n  \"shortName\": \"MartinRushMH3\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-08-07\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"comment\": \"Rush MH 3 Beam:\\n- Fixed gobo wheel\\n- Color wheel\\n- Mechanical dimming and strobe\\n- Frost effect\\n- 8-facet prism\\n- Motorized focus\\n- 3 & 5 pin XLR\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_RushMH3Beam_EN_K.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=7X43yj0elmM\",\n      \"https://www.youtube.com/watch?v=PUyDBMj7wjo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [321, 489, 418],\n    \"weight\": 20.5,\n    \"power\": 350,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Philips MSD Platinum 5R\",\n      \"colorTemperature\": 5000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [1, 3.8]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#00aaff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Pink\",\n          \"colors\": [\"#e0b0ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow Green\",\n          \"colors\": [\"#ddff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Pink\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Yellow\",\n          \"colors\": [\"#ffff99\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Off White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#00aaff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#0000aa\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 29],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer - conventional\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer - linear\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt - fast\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt - normal\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during pan&tilt\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during color change\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during gobo change\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during color change\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during gobo change\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during gobo change\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt reset\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color reset\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo reset\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Shutter/prism/rotating prism reset\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Frost/focus/zoom reset\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during pan/tilt or color/gobo change\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during pan/tilt or color/gobo change\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 28\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 29\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 30\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 31\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [3, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [7, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [19, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [30, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [34, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [36, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [38, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [40, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10.5\n        },\n        {\n          \"dmxRange\": [43, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [45, 46],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11.5\n        },\n        {\n          \"dmxRange\": [47, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12.5\n        },\n        {\n          \"dmxRange\": [51, 52],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13,\n          \"helpWanted\": \"What color is \\\"Off White\\\"?\"\n        },\n        {\n          \"dmxRange\": [53, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13.5\n        },\n        {\n          \"dmxRange\": [55, 56],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14.5\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [61, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15.5\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [7, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [13, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [16, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [19, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [22, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [25, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [28, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [31, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [34, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [37, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [40, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [43, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [46, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [49, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Prism Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"Prism effect\"\n        },\n        {\n          \"dmxRange\": [128, 132],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 1\"\n        },\n        {\n          \"dmxRange\": [133, 137],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 2\"\n        },\n        {\n          \"dmxRange\": [138, 141],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 3\"\n        },\n        {\n          \"dmxRange\": [142, 146],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 4\"\n        },\n        {\n          \"dmxRange\": [147, 150],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 5\"\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 6\"\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 7\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 8\"\n        },\n        {\n          \"dmxRange\": [165, 168],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 9\"\n        },\n        {\n          \"dmxRange\": [169, 173],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 10\"\n        },\n        {\n          \"dmxRange\": [174, 177],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 11\"\n        },\n        {\n          \"dmxRange\": [178, 182],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 12\"\n        },\n        {\n          \"dmxRange\": [183, 187],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 13\"\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 14\"\n        },\n        {\n          \"dmxRange\": [192, 196],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 15\"\n        },\n        {\n          \"dmxRange\": [197, 200],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 16\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 17\"\n        },\n        {\n          \"dmxRange\": [206, 209],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 18\"\n        },\n        {\n          \"dmxRange\": [210, 214],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 19\"\n        },\n        {\n          \"dmxRange\": [215, 218],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 20\"\n        },\n        {\n          \"dmxRange\": [219, 223],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 21\"\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 22\"\n        },\n        {\n          \"dmxRange\": [228, 232],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 23\"\n        },\n        {\n          \"dmxRange\": [233, 236],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 24\"\n        },\n        {\n          \"dmxRange\": [237, 241],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 25\"\n        },\n        {\n          \"dmxRange\": [242, 246],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 26\"\n        },\n        {\n          \"dmxRange\": [247, 250],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 27\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"Rotation effects 28\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"fineChannelAliases\": [\"Prism Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\",\n        \"helpWanted\": \"Is it wide to narrow or narrow to wide?\"\n      }\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Frost\": {\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [168, 203],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [204, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Function\",\n        \"Pan/Tilt Macros\",\n        \"Pan/Tilt Macro Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Prism Effects\",\n        \"Prism Rotation\",\n        \"Prism Rotation fine\",\n        \"Zoom\",\n        \"Focus\",\n        \"Frost\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/rush-mh-5-profile.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Rush MH 5 Profile\",\n  \"shortName\": \"MartinRushMH5\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"François Bouffard\", \"Flo Edelmann\"],\n    \"createDate\": \"2021-02-18\",\n    \"lastModifyDate\": \"2021-02-18\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/en/site_elements/rush-mh-5-profile-user-manual\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/rush-mh-5-profile\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=z7pXPoN3Hmc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [290, 416, 187],\n    \"weight\": 9,\n    \"power\": 165,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"75W LED\",\n      \"lumens\": 1800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14, 16]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#ff0000\"],\n          \"name\": \"Red\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#0000aa\"],\n          \"name\": \"Deep Blue\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#ffbfff\"],\n          \"name\": \"Lavender\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#c900c9\"],\n          \"name\": \"Magenta\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#ffff00\"],\n          \"name\": \"Yellow\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#ffaa00\"],\n          \"name\": \"Orange\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#55ee55\"],\n          \"name\": \"Light Green\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#55ccff\"],\n          \"name\": \"Light Blue\"\n        }\n      ]\n    },\n    \"Color Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#ff4ef6\"],\n          \"name\": \"Pink\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#ffc548\"],\n          \"colorTemperature\": \"3200K\",\n          \"name\": \"CTO\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#680c68\"],\n          \"name\": \"UV Purple\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#fcff55\"],\n          \"name\": \"Light Yellow\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#038f0a\"],\n          \"name\": \"Green\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#0fc08b\"],\n          \"name\": \"Aquamarine\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#ffebaa\"],\n          \"colorTemperature\": \"5600K\",\n          \"name\": \"CTO\"\n        },\n        {\n          \"type\": \"Color\",\n          \"colors\": [\"#2f75d1\"],\n          \"name\": \"Blue\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Line\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Square of 8 triangles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Axe blade\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"2 rotating scythes\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Sunrise rays\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Stripes\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Quartered circle outline\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"3 nested square outlines\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bubbles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"2 dashes\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Pointy star in octagon\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"4-fold swirl\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Swirly stars\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [168, 203],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [204, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [135, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [182, 184],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [185, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Color Wheel 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [135, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [182, 184],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [185, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 88],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [89, 112],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [113, 136],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [137, 160],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 184],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [185, 208],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 232],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        }\n      ]\n    },\n    \"Gobo Indexing\": {\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [182, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism Indexing / Rotation\": \"Prism Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 138],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet, indexing\",\n          \"switchChannels\": {\n            \"Prism Indexing / Rotation\": \"Prism Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [139, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet, rotating\",\n          \"switchChannels\": {\n            \"Prism Indexing / Rotation\": \"Prism Rotation\"\n          }\n        }\n      ]\n    },\n    \"Prism Indexing\": {\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset color\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset focus\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset prism\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan/tilt\"\n        },\n        {\n          \"dmxRange\": [40, 54],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable calibration\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt speed = Normal\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt speed = Fast (default setting)\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt speed = Slow\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Parameter shortcuts = On (default setting)\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Parameter shortcuts = Off\"\n        },\n        {\n          \"dmxRange\": [105, 144],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during pan/tilt movement = On\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during pan/tilt movement = Off (default setting)\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Illuminate control panel display\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Turn off control panel display\"\n        },\n        {\n          \"dmxRange\": [165, 194],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store color wheel 1 calibration\"\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store color wheel 2 calibration\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store gobo wheel 1 wheel calibration\"\n        },\n        {\n          \"dmxRange\": [210, 214],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store gobo wheel 1 gobo calibration\"\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store gobo wheel 2 calibration\"\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store focus calibration\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store prism calibration\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store prism rotation calibration\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store pan calibration\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store tilt calibration\"\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all calibration settings to factory defaults\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\",\n        \"Color Wheel 1\",\n        \"Color Wheel 2\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Indexing / Rotation\",\n        \"Static Gobo Wheel\",\n        \"Prism\",\n        \"Prism Indexing / Rotation\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/rush-mh-7-hybrid.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Rush MH 7 Hybrid\",\n  \"shortName\": \"MartinRushMH7\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-09-08\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_RUSHMH7_EN_D.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=FZ_f9vOGQmc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [408, 644, 301],\n    \"weight\": 24,\n    \"power\": 377,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Philips MSD Platinum 11R 250 W\",\n      \"colorTemperature\": 7800\n    },\n    \"lens\": {\n      \"degreesMinMax\": [2.2, 45]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffaaff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aqua\",\n          \"colors\": [\"#99ddff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#aa00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#ffcc99\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB\",\n          \"colors\": [\"#88bbdd\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#a996ff\"]\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Damped Wave\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Luck Stakes\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bite Me\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Laser Squares\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Kite Surf\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Dots in Space\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Organic Delight\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Slice It\"\n        }\n      ]\n    },\n    \"Fixed Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"75%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"60%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"40%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"20%\"\n        },\n        {\n          \"type\": \"Iris\",\n          \"openPercent\": \"5%\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"sequencial effects\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [12, 12],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [13, 22],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [23, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [33, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [34, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [43, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [44, 52],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [54, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [63, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [74, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [75, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [97, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [107, 114],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [115, 115],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [116, 124],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [125, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [126, 136],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 13,\n          \"slotNumberEnd\": 14,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [137, 137],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [138, 146],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 14,\n          \"slotNumberEnd\": 15,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [147, 147],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [200, 220],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [223, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [77, 81],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [82, 86],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [87, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [92, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [97, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [107, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 121],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [122, 131],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [132, 141],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [142, 151],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [162, 171],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [172, 181],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [182, 191],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Rotating Gobo Indexing/Speed\": \"Rotating Gobo Speed\",\n            \"Rotating Gobo Indexing/Speed fine\": \"Rotating Gobo Speed fine\"\n          }\n        }\n      ]\n    },\n    \"Rotating Gobo Indexing\": {\n      \"fineChannelAliases\": [\"Rotating Gobo Indexing fine\"],\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Rotating Gobo Speed\": {\n      \"fineChannelAliases\": [\"Rotating Gobo Speed fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [32, 93],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [94, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"90deg\"\n        }\n      ]\n    },\n    \"Fixed Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [3, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [6, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [9, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [12, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [15, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [18, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [21, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [24, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [27, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [30, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [33, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [36, 38],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [39, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [43, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [54, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [55, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [65, 65],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [66, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [77, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [78, 88],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [89, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [90, 100],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [101, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [102, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [113, 113],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [114, 123],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [124, 124],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [125, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [136, 136],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [137, 147],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [148, 148],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [149, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [160, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [172, 182],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [183, 183],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [184, 194],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 13,\n          \"slotNumberEnd\": 14\n        },\n        {\n          \"dmxRange\": [195, 195],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [196, 217],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [218, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random slots\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random slots\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random slots\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Rotating Prisms\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Rotating Prism Indexing/Speed\": \"Rotating Prism Indexing\",\n            \"Rotating Prism Indexing/Speed fine\": \"Rotating Prism Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"Prism\",\n          \"comment\": \"4-facet, indexed\",\n          \"switchChannels\": {\n            \"Rotating Prism Indexing/Speed\": \"Rotating Prism Indexing\",\n            \"Rotating Prism Indexing/Speed fine\": \"Rotating Prism Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet, indexed\",\n          \"switchChannels\": {\n            \"Rotating Prism Indexing/Speed\": \"Rotating Prism Indexing\",\n            \"Rotating Prism Indexing/Speed fine\": \"Rotating Prism Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Prism\",\n          \"comment\": \"4-facet, rotating\",\n          \"switchChannels\": {\n            \"Rotating Prism Indexing/Speed\": \"Rotating Prism Speed\",\n            \"Rotating Prism Indexing/Speed fine\": \"Rotating Prism Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet, rotating\",\n          \"switchChannels\": {\n            \"Rotating Prism Indexing/Speed\": \"Rotating Prism Speed\",\n            \"Rotating Prism Indexing/Speed fine\": \"Rotating Prism Speed fine\"\n          }\n        }\n      ]\n    },\n    \"Rotating Prism Indexing\": {\n      \"fineChannelAliases\": [\"Rotating Prism Indexing fine\"],\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Rotating Prism Speed\": {\n      \"fineChannelAliases\": [\"Rotating Prism Speed fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [32, 93],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [94, 127],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"90deg\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"250deg\"\n      }\n    },\n    \"Maintenance\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"auto-blackout on\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"auto-blackout off (default)\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp on\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp off\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset all\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"pan/tilt reset\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset color wheel\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset gobos\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset shutter\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"reset other effects\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"control panel display on\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"control panel display off\"\n        },\n        {\n          \"dmxRange\": [110, 115],\n          \"type\": \"Maintenance\",\n          \"comment\": \"parameter shortcuts on (default)\"\n        },\n        {\n          \"dmxRange\": [116, 121],\n          \"type\": \"Maintenance\",\n          \"comment\": \"parameter shortcuts off\"\n        },\n        {\n          \"dmxRange\": [122, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"21-channel\",\n      \"shortName\": \"21ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Color Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Indexing/Speed\",\n        \"Rotating Gobo Indexing/Speed fine\",\n        \"Fixed Gobo Wheel\",\n        \"Rotating Prisms\",\n        \"Rotating Prism Indexing/Speed\",\n        \"Rotating Prism Indexing/Speed fine\",\n        \"Frost\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Maintenance\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/rush-par-2-rgbw-zoom.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Rush PAR 2 RGBW Zoom\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"stevebrush\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-11-11\",\n    \"lastModifyDate\": \"2018-11-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adn.harmanpro.com/site_elements/executables/6829_1526699833/UM_RUSHPAR2RGBWZoom_EN_I_original.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/rush-par-2-rgbw-zoom\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=pXoW-NA1lK4\",\n      \"https://www.youtube.com/watch?v=N_loyyozkzE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [287, 329, 266],\n    \"weight\": 5.5,\n    \"power\": 151,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"12× 10W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Zoom\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"60deg\",\n        \"angleEnd\": \"10deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Color 1\"\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9b00\"],\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd866\"],\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffe100\"],\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fff500\"],\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffe71\"],\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f5ff00\"],\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ebff53\"],\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cdff00\"],\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ccff6f\"],\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff9b\"],\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#37ffc8\"],\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffd2\"],\n          \"comment\": \"Color 15\"\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffe6\"],\n          \"comment\": \"Color 16\"\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#48fff4\"],\n          \"comment\": \"Color 17\"\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Color 18\"\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00faff\"],\n          \"comment\": \"Color 19\"\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#62e9ff\"],\n          \"comment\": \"Color 20\"\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00d7e1\"],\n          \"comment\": \"Color 21\"\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#6ddaff\"],\n          \"comment\": \"Color 22\"\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Color 23\"\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a500ff\"],\n          \"comment\": \"Color 24\"\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c300ff\"],\n          \"comment\": \"Color 25\"\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e100ff\"],\n          \"comment\": \"Color 26\"\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f666ff\"],\n          \"comment\": \"Color 27\"\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fd00ff\"],\n          \"comment\": \"Color 28\"\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Color 29\"\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00f5\"],\n          \"comment\": \"Color 30\"\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00eb\"],\n          \"comment\": \"Color 31\"\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00dc\"],\n          \"comment\": \"Color 32\"\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6bd6\"],\n          \"comment\": \"Color 33\"\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00a5\"],\n          \"comment\": \"Color 34\"\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Color 35\"\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"Color 36\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"fast\",\n          \"comment\": \"random\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"50%\",\n          \"comment\": \"random\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"slow\",\n          \"comment\": \"random\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Zoom\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Presets\",\n        \"Zoom\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/rush-scanner-1-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Rush Scanner 1 LED\",\n  \"shortName\": \"MartinRushScan1\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-03-07\",\n    \"lastModifyDate\": \"2019-03-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://adn.harmanpro.com/site_elements/executables/6809_1526699780/UM_RUSHScanner1LED_EN_B_original.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en-US/products/rush-scanner-1-led\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Hz23QxIo-Zc\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [303, 193, 588],\n    \"weight\": 9.6,\n    \"power\": 168,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"90W LED\"\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep Blue\",\n          \"colors\": [\"#0000b4\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#ff80ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light green\",\n          \"colors\": [\"#80ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#0080ff\"]\n        }\n      ]\n    },\n    \"Color Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff9696\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colorTemperature\": \"3200K\",\n          \"colors\": [\"#fff0c8\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV Purple\",\n          \"colors\": [\"#b400ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light yellow\",\n          \"colors\": [\"#ffff80\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aquamarine\",\n          \"colors\": [\"#00ff80\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colorTemperature\": \"5600K\",\n          \"colors\": [\"#fff0c8\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 8,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [168, 203],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [204, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel 1\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [135, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [182, 184],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [185, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Color Wheel 2\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [121, 134],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [135, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [182, 184],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [185, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Rotation\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 88],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"isShaking\": \"slot\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [89, 112],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"isShaking\": \"slot\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [113, 136],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"isShaking\": \"slot\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [137, 160],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"isShaking\": \"slot\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 184],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"isShaking\": \"slot\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [185, 208],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"isShaking\": \"slot\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [209, 209],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 232],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo Indexing / Rotation\": \"Gobo Indexing\"\n          }\n        }\n      ]\n    },\n    \"Gobo Indexing\": {\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [15, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [30, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [31, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [60, 60],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [61, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [75, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [76, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [90, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [91, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [105, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 160],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [182, 192],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [193, 214],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [215, 221],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [222, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"50%\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Prism Indexing / Rotation\": \"Prism Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 138],\n          \"type\": \"Prism\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Prism Indexing / Rotation\": \"Prism Indexing\"\n          }\n        },\n        {\n          \"dmxRange\": [139, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Prism Indexing / Rotation\": \"Prism Rotation\"\n          }\n        }\n      ]\n    },\n    \"Prism Indexing\": {\n      \"capability\": {\n        \"type\": \"PrismRotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [3, 126],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [127, 129],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 253],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"170deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"75deg\"\n      }\n    },\n    \"Functions / Settings\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset color\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset focus\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset prism\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan/tilt\"\n        },\n        {\n          \"dmxRange\": [40, 54],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable calibration\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt speed = normal\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt speed = fast (default)\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt speed = slow\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Parameter shortcuts = On (default)\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Parameter shortcuts = Off\"\n        },\n        {\n          \"dmxRange\": [105, 144],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout = On (fixture goes to standby when no DMX signal)\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout = Off (default setting: fixture enters standalone operation when no DMX signal)\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Illuminate control panel display\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Turn off control panel display\"\n        },\n        {\n          \"dmxRange\": [165, 194],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store color wheel 1 calibration\"\n        },\n        {\n          \"dmxRange\": [200, 204],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store color wheel 2 calibration\"\n        },\n        {\n          \"dmxRange\": [205, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store rotating gobo wheel calibration\"\n        },\n        {\n          \"dmxRange\": [210, 214],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store rotating gobo calibration\"\n        },\n        {\n          \"dmxRange\": [215, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store static gobo wheel calibration\"\n        },\n        {\n          \"dmxRange\": [220, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store focus calibration\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store prism calibration\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store prism rotation calibration\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store pan calibration\"\n        },\n        {\n          \"dmxRange\": [240, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Store tilt calibration\"\n        },\n        {\n          \"dmxRange\": [245, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all calibration settings to factory defaults\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Strobe\",\n        \"Color Wheel 1\",\n        \"Color Wheel 2\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Indexing / Rotation\",\n        \"Static Gobo Wheel\",\n        \"Prism\",\n        \"Prism Indexing / Rotation\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Functions / Settings\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/stagebar-54l.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stagebar 54L\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-10-06\",\n    \"lastModifyDate\": \"2019-10-06\"\n  },\n  \"comment\": \"Uses RJ-45 DMX connector\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_Stagebar54_EN_C.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/stagebar-54\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=kxgCK4c4baU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [630, 105, 190],\n    \"weight\": 7.3,\n    \"power\": 230,\n    \"bulb\": {\n      \"type\": \"Luxeon K2 LEDs\",\n      \"lumens\": 650\n    },\n    \"lens\": {\n      \"degreesMinMax\": [29, 29]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [105, 70, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [6, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": [\"1\", \"2\", \"3\"],\n      \"2/2\": [\"4\", \"5\", \"6\"],\n      \"1/3\": [\"1\", \"2\"],\n      \"2/3\": [\"3\", \"4\"],\n      \"3/3\": [\"5\", \"6\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Intensity $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature $pixelKey\": {\n      \"defaultValue\": 191,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2000K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB All\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBAW All\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSI All\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSIC All\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\",\n            \"Color Temperature $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Halves\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBAW Halves\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSI Halves\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSIC Halves\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\",\n            \"Color Temperature $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Thirds\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBAW Thirds\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSI Thirds\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSIC Thirds\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\",\n            \"Color Temperature $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Individual\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBAW Individual\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSI Individual\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSIC Individual\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\",\n            \"Color Temperature $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/martin/stagebar-54s.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stagebar 54S\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Andy Melsom\"],\n    \"createDate\": \"2019-10-06\",\n    \"lastModifyDate\": \"2019-10-06\"\n  },\n  \"comment\": \"Uses RJ-45 DMX connector\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.martin.com/files/files/productdocuments/11_MANUALS/999/UM_Stagebar54_EN_C.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.martin.com/en/products/stagebar-54\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=kxgCK4c4baU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [420, 105, 190],\n    \"weight\": 5.5,\n    \"power\": 230,\n    \"bulb\": {\n      \"type\": \"Luxeon K2 LEDs\",\n      \"lumens\": 650\n    },\n    \"lens\": {\n      \"degreesMinMax\": [29, 29]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [70, 70, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [6, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": [\"1\", \"2\", \"3\"],\n      \"2/2\": [\"4\", \"5\", \"6\"],\n      \"1/3\": [\"1\", \"2\"],\n      \"2/3\": [\"3\", \"4\"],\n      \"3/3\": [\"5\", \"6\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Hue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Intensity $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature $pixelKey\": {\n      \"defaultValue\": 191,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"2000K\",\n        \"colorTemperatureEnd\": \"10000K\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB All\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBAW All\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSI All\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSIC All\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Master\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\",\n            \"Color Temperature $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Halves\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBAW Halves\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSI Halves\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSIC Halves\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\",\n            \"Color Temperature $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Thirds\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBAW Thirds\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSI Thirds\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSIC Thirds\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\",\n            \"Color Temperature $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Individual\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBAW Individual\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSI Individual\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"HSIC Individual\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Hue $pixelKey\",\n            \"Saturation $pixelKey\",\n            \"Intensity $pixelKey\",\n            \"Color Temperature $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mdg/atme.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ATMe\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"Manu\"],\n    \"createDate\": \"2026-01-23\",\n    \"lastModifyDate\": \"2026-01-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://mdgfog.s3.ca-central-1.amazonaws.com/uploads/docs/ATMe%2C%20User%20Guide%2C%20Rev%20Ce.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.mdgfog.com/en/atme\"\n    ],\n    \"video\": [\n      \"https://vimeo.com/141104074\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 300, 685],\n    \"weight\": 16.8,\n    \"power\": 1400,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Unit control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 128],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Unit OFF\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Unit ON\"\n        }\n      ]\n    },\n    \"Haze output\": {\n      \"capability\": {\n        \"type\": \"FogOutput\",\n        \"fogOutputStart\": \"weak\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Haze control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 128],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"fogOutput\": \"off\",\n          \"comment\": \"Haze OFF\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\",\n          \"comment\": \"Haze ON\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Unit control\",\n        \"Haze output\",\n        \"Haze control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mdg/hazer-atmosphere-aps.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hazer ATMOSPHERE APS\",\n  \"shortName\": \"MDG-M35A-X\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-08-08\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://mdgfog.s3.amazonaws.com/uploads/docs/ATM-MAX-User-Guide-120815-Rev-Ad.pdf\",\n      \"https://mdgfog.s3.amazonaws.com/uploads/docs/DMX-M35A-X-2012.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.mdgfog.com/en/atmosphereaps\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=C9u31D-4icQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 300, 68.5],\n    \"weight\": 23,\n    \"power\": 715,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Haze\"\n        }\n      ]\n    },\n    \"Fog Emission\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 17],\n          \"type\": \"FogOutput\",\n          \"fogOutput\": \"off\"\n        },\n        {\n          \"dmxRange\": [18, 255],\n          \"type\": \"FogOutput\",\n          \"fogOutputStart\": \"weak\",\n          \"fogOutputEnd\": \"strong\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Fog\",\n        \"Fog Emission\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mdg/theone-atmospheric-generator.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"theONE Atmospheric Generator\",\n  \"shortName\": \"MDGtheONE\",\n  \"categories\": [\"Hazer\", \"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2017-10-13\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"comment\": \"Fog output: 85m³ per minute in Fog mode, at full pressure\",\n  \"links\": {\n    \"manual\": [\n      \"https://mdgfog.s3.amazonaws.com/uploads/docs/theONE-User-Guide-Rev-Af.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.mdgfog.com/en/theone\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Fa6w-k2p6l8\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 1\n  },\n  \"physical\": {\n    \"dimensions\": [250, 610, 300],\n    \"weight\": 23,\n    \"power\": 1480,\n    \"powerConnectors\": {\n      \"IEC C19\": \"input only\"\n    },\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Power\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Unit off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Unit On\"\n        }\n      ]\n    },\n    \"Haze / Fog\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"FogType\",\n          \"fogType\": \"Haze\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"FogType\",\n          \"fogType\": \"Fog\"\n        }\n      ]\n    },\n    \"Fog output\": {\n      \"capability\": {\n        \"type\": \"FogOutput\",\n        \"fogOutputStart\": \"weak\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Fog on/off\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Fog\"\n        }\n      ]\n    },\n    \"External Fan\": {\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"speedStart\": \"slow CW\",\n        \"speedEnd\": \"fast CW\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Power\",\n        \"Haze / Fog\",\n        \"Fog output\",\n        \"Fog on/off\",\n        \"External Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mega-led-lighting/led-par-light-372.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR Light-372\",\n  \"shortName\": \"MJ-3001-72\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-02-06\",\n    \"lastModifyDate\": \"2019-02-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.jackodance.it/wp-content/uploads/2019/01/MJ-3001-72-LED-PAR-LIGHT-372.pdf\"\n    ]\n  },\n  \"helpWanted\": \"Is the 4ch mode correct?\",\n  \"physical\": {\n    \"dimensions\": [310, 250, 325],\n    \"weight\": 3.5,\n    \"power\": 216,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"72x3W LEDs (18x red/green/blue/white each)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Change\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [150, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color pulse\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"A001\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Change\",\n        \"Effect Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"d001\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mega-led-lighting/zoom-360.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ZOOM 360\",\n  \"shortName\": \"MJ-1006B\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2019-02-06\",\n    \"lastModifyDate\": \"2019-02-06\"\n  },\n  \"comment\": \"4in1 variant\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.jackodance.it/wp-content/uploads/2019/01/MJ-1006B-zoom-led-moving-head-light.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.mjledlighting.com/product/4in1-5in1-6in1-led-wash-zoom-moving-head-light/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [350, 460, 220],\n    \"weight\": 10,\n    \"power\": 420,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"36x RBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"User Colors\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"helpWanted\": \"How many colors are there and at which DMX values can they be selected?\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"10deg\",\n        \"angleEnd\": \"60deg\",\n        \"helpWanted\": \"Or is it 60…10°?\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Start controller handspike\",\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 50],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Turn off controller handspike\",\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 90],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Program color selection switch\",\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color pulse\",\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 170],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 210],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Inside mode 1\",\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color Macros / Effect Speed\": \"Color Macros\"\n          }\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [101, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [121, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [141, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Black\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 1 (R242 G204 B5 W227)\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 2 (R242 G215 B5 W227)\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 3 (R255 G255 B50 W255)\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 4 (R255 G255 B90 W255)\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 5 (R255 G255 B118 W255)\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 6 (R255 G255 B132 W255)\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 7 (R2 55 G255 B151 W255)\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 8 (R255 G255 B171 W255)\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 9 (R255 G255 B185 W255)\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 10 (R255 G255 B197 W255)\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color mix 11 (R255 G255 B234 W255)\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"ID Code\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 13\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 14\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 15\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 16\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 17\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 18\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 19\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 20\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 21\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 22\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 23\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 24\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"ID 25\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"User Colors\",\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Zoom\",\n        \"Strobe\",\n        \"Effects\",\n        \"Color Macros / Effect Speed\",\n        \"ID Code\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"User Colors\",\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Zoom\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mega-lite/framebot-600.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Framebot 600\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ryan Goodwin\"],\n    \"createDate\": \"2024-10-15\",\n    \"lastModifyDate\": \"2024-10-15\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.mega.lighting/_files/ugd/21ff82_b4f803e84eb04f0f92f7a38066073ab8.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.mega.lighting/blank-5-1-1-3-1-1\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=RWwEGS5yn6A\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [389, 339, 635],\n    \"weight\": 25.4,\n    \"power\": 807,\n    \"powerConnectors\": {\n      \"powerCON TRUE1\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"580W White LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [6.5, 42]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#000080\"]\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Colormation\": {\n      \"slots\": [\n        {\n          \"type\": \"AnimationGoboStart\"\n        },\n        {\n          \"type\": \"AnimationGoboEnd\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [64, 221],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [222, 239],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [64, 221],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [222, 239],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [4, 123],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [124, 187],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 143],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [144, 199],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Colormation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Colormation insertion\",\n          \"parameterStart\": \"0%\",\n          \"parameterEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Colormation Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Colormation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Colormation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Colormation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [136, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Colormation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Kelvin\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperature\": \"6408K\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Refresh\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"Refresh Rate 1200\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Generic\",\n          \"comment\": \"Refresh Rate 13672\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"20Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"Prism\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 123],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [124, 187],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Iris\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"open\",\n          \"openPercentEnd\": \"closed\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [136, 173],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse Closed to Open\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [174, 211],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse Open to Closed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [212, 249],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Iris Bounce\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"off\",\n          \"frostIntensityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset All\",\n          \"hold\": \"8s\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan/Tilt\",\n          \"hold\": \"8s\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Color/Gobo/CMYK\",\n          \"hold\": \"8s\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Zoom/Focus/Prism/Frost\",\n          \"hold\": \"8s\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Colormation/Iris/Framing\",\n          \"hold\": \"8s\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Default\",\n          \"hold\": \"8s\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Off\",\n          \"hold\": \"8s\"\n        },\n        {\n          \"dmxRange\": [90, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Frame 1A\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frame 1B\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 1,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frame 2A\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frame 2B\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 2,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frame 3A\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 3,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frame 3B\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 3,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frame 4A\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 4,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frame 4B\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"BladeInsertion\",\n        \"blade\": 4,\n        \"insertionStart\": \"out\",\n        \"insertionEnd\": \"in\"\n      }\n    },\n    \"Frame Rotation\": {\n      \"fineChannelAliases\": [\"Frame Rotation fine\"],\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2039],\n          \"type\": \"BladeSystemRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [2040, 61200],\n          \"type\": \"BladeSystemRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"180deg\"\n        },\n        {\n          \"dmxRange\": [61201, 65535],\n          \"type\": \"BladeSystemRotation\",\n          \"comment\": \"Frame Bounce\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"180deg\"\n        }\n      ]\n    },\n    \"Frame Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Frame Macro (1-63)\",\n          \"helpWanted\": \"What range is each macro?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"39-channel\",\n      \"shortName\": \"39ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Kelvin\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Dimmer Refresh\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Iris\",\n        \"Frost\",\n        \"Colormation\",\n        \"Colormation Rotation\",\n        \"Frame 1A\",\n        \"Frame 1B\",\n        \"Frame 2A\",\n        \"Frame 2B\",\n        \"Frame 3A\",\n        \"Frame 3B\",\n        \"Frame 4A\",\n        \"Frame 4B\",\n        \"Frame Rotation\",\n        \"Frame Rotation fine\",\n        \"Frame Macro\",\n        \"Pan/Tilt Speed\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mega-lite/mw1.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MW1\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ryan Goodwin\"],\n    \"createDate\": \"2024-10-08\",\n    \"lastModifyDate\": \"2024-10-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.mega.lighting/_files/ugd/21ff82_e921a48d91974862860f4e5f05ed7f30.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.mega.lighting/mw1\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=StuUWiJoji8\",\n      \"https://www.youtube.com/watch?v=pS-_VBK4j8k\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [324, 229, 394],\n    \"weight\": 8.6,\n    \"power\": 376,\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"7x Osram RGBW 40W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [9, 44]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, \"7\", null, \"2\", null],\n        [\"6\", null, \"1\", null, \"3\"],\n        [null, \"5\", null, \"4\", null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"All\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32512,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32512,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Shutter Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 6],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1\"\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2\"\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 3\"\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 4\"\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 5\"\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 6\"\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 7\"\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2+3\"\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 4+5\"\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 6+7\"\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2+3\"\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+4+5\"\n        },\n        {\n          \"dmxRange\": [84, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+6+7\"\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2\"\n        },\n        {\n          \"dmxRange\": [98, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 3+6\"\n        },\n        {\n          \"dmxRange\": [105, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2+3+5+6\"\n        },\n        {\n          \"dmxRange\": [112, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+3+6\"\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2+4+6\"\n        },\n        {\n          \"dmxRange\": [126, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2+3+5+6\"\n        },\n        {\n          \"dmxRange\": [133, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2+3+4+5+6+7\"\n        },\n        {\n          \"dmxRange\": [140, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2,3,4,5,6 M\"\n        },\n        {\n          \"dmxRange\": [147, 153],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2+3,4+5,6+7 M\"\n        },\n        {\n          \"dmxRange\": [154, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2,1+3,1+4,1+5,1+6,1+7 M\"\n        },\n        {\n          \"dmxRange\": [161, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2+3, 1+4+5, 1+6+7 M\"\n        },\n        {\n          \"dmxRange\": [168, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2+3+4, 3+4+5, 4+5+6, 5+6+7, 6+7+2, 7+2+3 M\"\n        },\n        {\n          \"dmxRange\": [175, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2+3+4, 1+3+4+5, 1+4+5+6, 1+5+6+7, 1+6+7+2, 1+7+2+3 M\"\n        },\n        {\n          \"dmxRange\": [182, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2+5, 3+6, 4+7 M\"\n        },\n        {\n          \"dmxRange\": [189, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 2+3+5+6, 3+4+6+7,4+5+7+1 M\"\n        },\n        {\n          \"dmxRange\": [196, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2+5,1+3+6,1+4+7 M\"\n        },\n        {\n          \"dmxRange\": [203, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2+3+5+6, 1+3+4+6+7, 1+4+5+7+1 M\"\n        },\n        {\n          \"dmxRange\": [210, 216],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1+2+3+5+6, 1+3+4+6+7, 1+4+5+7+1 M\"\n        },\n        {\n          \"dmxRange\": [217, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1, 2+3+4+5+6+7\"\n        },\n        {\n          \"dmxRange\": [224, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1, 2+3+4+5+6+7 Color\"\n        },\n        {\n          \"dmxRange\": [231, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1,2+3+4+5+6+7 Color\"\n        },\n        {\n          \"dmxRange\": [238, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light 1, 2+3, 4+5, 6+7 Color\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Light Random Color\"\n        }\n      ]\n    },\n    \"Shutter Macro Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Shutter Macro Background Color\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"helpWanted\": \"What colors are at what values?\"\n      }\n    },\n    \"CTO\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [3, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"8653K\",\n          \"colorTemperatureEnd\": \"2823K\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pre Built Patterns\",\n          \"helpWanted\": \"What are the patterns available?\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"44deg\",\n        \"angleEnd\": \"9deg\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 250],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fixture Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Shutter\",\n        \"Hue\",\n        \"Saturation\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Hue\",\n        \"Red All\",\n        \"Green All\",\n        \"Blue All\",\n        \"White All\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Zoom\",\n        \"Control\",\n        \"Macros\"\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Red All\",\n        \"Green All\",\n        \"Blue All\",\n        \"White All\",\n        \"CTO\",\n        \"Hue\",\n        \"Shutter Macros\",\n        \"Shutter Macro Speed\",\n        \"Shutter Macro Background Color\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"38-channel\",\n      \"shortName\": \"38ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter\",\n        \"Zoom\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mega-lite/spotbot-led-cmy-300.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Spotbot LED CMY 300\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ryan Goodwin\"],\n    \"createDate\": \"2023-10-22\",\n    \"lastModifyDate\": \"2023-10-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.mega.lighting/_files/ugd/21ff82_85b85cc41e164e9b8eff2b2ee778e48a.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.mega.lighting/blank-5-1-1-3\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=S9lRFpqDkUM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [431.8, 685.8, 260.35],\n    \"weight\": 23.2,\n    \"power\": 382,\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LumiEngin 300W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 31]\n    }\n  },\n  \"wheels\": {\n    \"Color Selection 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#3e0694\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#000070\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        }\n      ]\n    },\n    \"Color Selection 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lime Green\",\n          \"colors\": [\"#70ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Color Selection 3\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"4926K\",\n          \"colors\": [\"#ffe3ca\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"4260K\",\n          \"colors\": [\"#ffd7b1\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"3889K\",\n          \"colors\": [\"#ffce9f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Selection 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [75, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        }\n      ]\n    },\n    \"Color Selection 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [75, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        }\n      ]\n    },\n    \"Color Selection 3\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [75, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [84, 90],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [98, 104],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [105, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 118],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 190],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 187],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [188, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"240deg\"\n      }\n    },\n    \"P/T Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Iris\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse Open\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse Close\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"low\",\n          \"frostIntensityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"defaultValue\": 32639,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 32639,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Auto Focus\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Auto Focus (5 positions)\",\n        \"helpWanted\": \"What are these auto focus positions?\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 160],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan / Tilt Reset\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Motor Function Reset\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"21-channel\",\n      \"shortName\": \"21ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"P/T Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Selection 1\",\n        \"Color Selection 2\",\n        \"Color Selection 3\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Iris\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Focus\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"26-channel\",\n      \"shortName\": \"26ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"P/T Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Selection 1\",\n        \"Color Selection 2\",\n        \"Color Selection 3\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Iris\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Auto Focus\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/mega-lite/washbot-led-cymk-300.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Washbot LED CYMK 300\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ryan Goodwin\"],\n    \"createDate\": \"2023-10-22\",\n    \"lastModifyDate\": \"2023-10-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://mega.lighting/wp-content/uploads/2020/01/Washbot-Manual-V2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://mega.lighting/product/washbot/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=5fLSs0VkQ1c\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [431, 260, 685],\n    \"weight\": 23.2,\n    \"power\": 363,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"bulb\": {\n      \"type\": \"LumiEngin 300W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 31]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red & Orange\",\n          \"colors\": [\"#ff3000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#7000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Aqua\",\n          \"colors\": [\"#0070ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Hot Pink\",\n          \"colors\": [\"#ff0070\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"1/4 CTB\",\n          \"colors\": [\"#b6c2da\"]\n        }\n      ]\n    },\n    \"Color Selection 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#3e0694\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#000070\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        }\n      ]\n    },\n    \"Color Selection 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lime Green\",\n          \"colors\": [\"#70ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        }\n      ]\n    },\n    \"Color Selection 3\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Pink\",\n          \"colors\": [\"#ff40aa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Teal\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"RBG\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        }\n      ]\n    },\n    \"Color Selection 4\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"4789K\",\n          \"colors\": [\"#ffffc6\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"3513K\",\n          \"colors\": [\"#ffc489\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"3301K\",\n          \"colors\": [\"#ffbe7e\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"5262K\",\n          \"colors\": [\"#ffe9d9\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [2, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [33, 46],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [47, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [65, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [80, 97],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [98, 125],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [126, 190],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [191, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Color Selection 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [75, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        }\n      ]\n    },\n    \"Color Selection 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [75, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        }\n      ]\n    },\n    \"Color Selection 3\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [75, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        }\n      ]\n    },\n    \"Color Selection 4\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [11, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [75, 140],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"240deg\"\n      }\n    },\n    \"P/T Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 103],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [108, 207],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\"\n        },\n        {\n          \"dmxRange\": [208, 212],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [213, 251],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"18Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Kelvin\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"3920K\",\n        \"colorTemperatureEnd\": \"5262K\"\n      }\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Prism\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"defaultValue\": 32639,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 32639,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 119],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [120, 160],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan / Tilt Reset\"\n        },\n        {\n          \"dmxRange\": [161, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Motor Function Reset\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"20-channel\",\n      \"shortName\": \"20ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Kelvin\",\n        \"Color Selection 1\",\n        \"Color Selection 2\",\n        \"Color Selection 3\",\n        \"Color Selection 4\",\n        \"Color Wheel\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"23-channel\",\n      \"shortName\": \"23ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"P/T Speed\",\n        \"Dimmer\",\n        \"Shutter\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Kelvin\",\n        \"Color Selection 1\",\n        \"Color Selection 2\",\n        \"Color Selection 3\",\n        \"Color Selection 4\",\n        \"Color Wheel\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/minuit-une/ivl-carre.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"IVL Carré\",\n  \"shortName\": \"ivlcarre\",\n  \"categories\": [\"Laser\", \"Effect\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"ameisso\"],\n    \"createDate\": \"2018-03-30\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\"https://minuitune.com/wp-content/uploads/2018/04/DMX_sheet_IVL_Carre_and_IVL_Pyramide.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=YAKrrMRgdIo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [594.3, 200, 551.9],\n    \"weight\": 13,\n    \"power\": 125,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"Laser\"\n    }\n  },\n  \"availableChannels\": {\n    \"Control\": {\n      \"defaultValue\": 191,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [24, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [50, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"On\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Blade\": {\n      \"fineChannelAliases\": [\"Blade fine\"],\n      \"capability\": {\n        \"type\": \"BladeRotation\",\n        \"blade\": 1,\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [15, 27],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [28, 227],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"30bpm\",\n          \"speedEnd\": \"1440bpm\"\n        },\n        {\n          \"dmxRange\": [228, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Tilt All\": {\n      \"fineChannelAliases\": [\"Tilt All fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 255],\n          \"type\": \"Tilt\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        }\n      ]\n    },\n    \"Tilt 1\": {\n      \"fineChannelAliases\": [\"Tilt 1 fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Tilt 2\": {\n      \"fineChannelAliases\": [\"Tilt 2 fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Tilt 3\": {\n      \"fineChannelAliases\": [\"Tilt 3 fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Tilt 4\": {\n      \"fineChannelAliases\": [\"Tilt 4 fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo All\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 Beam\"\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Beams\"\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 Beams\"\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 Beams\"\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"16 Beams\"\n        },\n        {\n          \"dmxRange\": [185, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"32 Beams\"\n        }\n      ]\n    },\n    \"Index\": {\n      \"fineChannelAliases\": [\"Index fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 122],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [123, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 242],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [243, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Gobo Beam Angle all\": {\n      \"fineChannelAliases\": [\"Gobo Beam Angle all fine\"],\n      \"capability\": {\n        \"type\": \"BeamAngle\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Red Gobo\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 Beam\"\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Beams\"\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 Beams\"\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 Beams\"\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"16 Beams\"\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"Effect\",\n          \"effectName\": \"32 Beams\"\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"64 Beams\"\n        }\n      ]\n    },\n    \"Index Red\": {\n      \"fineChannelAliases\": [\"Index Red fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Green Gobo\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 Beam\"\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Beams\"\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 Beams\"\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 Beams\"\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"16 Beams\"\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"Effect\",\n          \"effectName\": \"32 Beams\"\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"64 Beams\"\n        }\n      ]\n    },\n    \"Rotation Red\": {\n      \"fineChannelAliases\": [\"Rotation Red fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 122],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [123, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 242],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [243, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Index Green\": {\n      \"fineChannelAliases\": [\"Index Green fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Rotation Green\": {\n      \"fineChannelAliases\": [\"Rotation Green fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 122],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [123, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 242],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [243, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Blue Gobo\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 36],\n          \"type\": \"Effect\",\n          \"effectName\": \"1 Beam\"\n        },\n        {\n          \"dmxRange\": [37, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"2 Beams\"\n        },\n        {\n          \"dmxRange\": [74, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"3 Beams\"\n        },\n        {\n          \"dmxRange\": [111, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"8 Beams\"\n        },\n        {\n          \"dmxRange\": [148, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"16 Beams\"\n        },\n        {\n          \"dmxRange\": [185, 221],\n          \"type\": \"Effect\",\n          \"effectName\": \"32 Beams\"\n        },\n        {\n          \"dmxRange\": [222, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"64 Beams\"\n        }\n      ]\n    },\n    \"Index Blue\": {\n      \"fineChannelAliases\": [\"Index Blue fine\"],\n      \"defaultValue\": 32767,\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Rotation Blue\": {\n      \"fineChannelAliases\": [\"Rotation Blue fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 122],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [123, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 242],\n          \"type\": \"Rotation\",\n          \"speed\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [243, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Gobo Beam Angle Red\": {\n      \"fineChannelAliases\": [\"Gobo Beam Angle Red fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo Beam Angle Green\": {\n      \"fineChannelAliases\": [\"Gobo Beam Angle Green fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo Beam Angle Blue\": {\n      \"fineChannelAliases\": [\"Gobo Beam Angle Blue fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"25 channel\",\n      \"shortName\": \"25ch\",\n      \"channels\": [\n        \"Control\",\n        \"Dimmer\",\n        \"Blade\",\n        \"Blade fine\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Shutter\",\n        \"Tilt All\",\n        \"Tilt All fine\",\n        \"Tilt 1\",\n        \"Tilt 1 fine\",\n        \"Tilt 2\",\n        \"Tilt 2 fine\",\n        \"Tilt 3\",\n        \"Tilt 3 fine\",\n        \"Tilt 4\",\n        \"Tilt 4 fine\",\n        \"Gobo All\",\n        \"Index\",\n        \"Index fine\",\n        \"Rotation\",\n        \"Gobo Beam Angle all\",\n        \"Gobo Beam Angle all fine\",\n        null\n      ]\n    },\n    {\n      \"name\": \"45 channel\",\n      \"shortName\": \"45ch\",\n      \"channels\": [\n        \"Control\",\n        \"Dimmer\",\n        \"Blade\",\n        \"Blade fine\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Shutter\",\n        \"Tilt All\",\n        \"Tilt All fine\",\n        \"Tilt 1\",\n        \"Tilt 1 fine\",\n        \"Tilt 2\",\n        \"Tilt 2 fine\",\n        \"Tilt 3\",\n        \"Tilt 3 fine\",\n        \"Tilt 4\",\n        \"Tilt 4 fine\",\n        \"Red Gobo\",\n        \"Index Red\",\n        \"Index Red fine\",\n        \"Rotation Red\",\n        \"Rotation Red fine\",\n        \"Gobo Beam Angle Red\",\n        \"Gobo Beam Angle Red fine\",\n        \"Green Gobo\",\n        \"Index Green\",\n        \"Index Green fine\",\n        \"Rotation Green\",\n        \"Rotation Green fine\",\n        \"Gobo Beam Angle Green\",\n        \"Gobo Beam Angle Green fine\",\n        \"Blue Gobo\",\n        \"Index Blue\",\n        \"Index Blue fine\",\n        \"Rotation Blue\",\n        \"Rotation Blue fine\",\n        \"Gobo Beam Angle Blue\",\n        \"Gobo Beam Angle Blue fine\",\n        null,\n        null,\n        null,\n        null,\n        null,\n        null\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/minuit-une/m-carre.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\",\n  \"name\": \"M-Carré\",\n  \"redirectTo\": \"minuit-une/ivl-carre\",\n  \"reason\": \"FixtureRenamed\"\n}\n"
  },
  {
    "path": "fixtures/nicols/led-bar-123-fc-ip.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED BAR 123 FC IP\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Nils Van Zuijlen\"],\n    \"createDate\": \"2018-04-22\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\"http://sunlight-online.de/pdf/LEDBAR123FC.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=O7XbNMwKWI0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [114, 120, 120],\n    \"weight\": 3.8,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"12×tri-3W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Macro\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [84, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [98, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [105, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [112, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\"\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\"\n        },\n        {\n          \"dmxRange\": [126, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\"\n        },\n        {\n          \"dmxRange\": [133, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\"\n        },\n        {\n          \"dmxRange\": [140, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\"\n        },\n        {\n          \"dmxRange\": [147, 153],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 21\"\n        },\n        {\n          \"dmxRange\": [154, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 22\"\n        },\n        {\n          \"dmxRange\": [161, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 23\"\n        },\n        {\n          \"dmxRange\": [168, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 24\"\n        },\n        {\n          \"dmxRange\": [175, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 25\"\n        },\n        {\n          \"dmxRange\": [182, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 26\"\n        },\n        {\n          \"dmxRange\": [189, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 27\"\n        },\n        {\n          \"dmxRange\": [196, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 28\"\n        },\n        {\n          \"dmxRange\": [203, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 29\"\n        },\n        {\n          \"dmxRange\": [210, 216],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 30\"\n        },\n        {\n          \"dmxRange\": [217, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 31\"\n        },\n        {\n          \"dmxRange\": [224, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 32\"\n        },\n        {\n          \"dmxRange\": [231, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 33\"\n        },\n        {\n          \"dmxRange\": [238, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 34\"\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 35\"\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Dimmer\",\n        \"Macro\",\n        \"Macro Speed\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"36-channel\",\n      \"shortName\": \"36ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/nicols/pat-252.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PAT 252\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"MIE\", \"Mikael\"],\n    \"createDate\": \"2018-11-23\",\n    \"lastModifyDate\": \"2018-11-23\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-11-23\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.2)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.levenly.com/photo/maxi/nicols_pat_252_dmx_fiche_technique.jpg\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=YbxBEFb9ACk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [155, 500, 200],\n    \"weight\": 11,\n    \"power\": 350,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"ELC 250W\"\n    },\n    \"lens\": {\n      \"name\": \"Other\"\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#58b848\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange 306\",\n          \"colors\": [\"#f46f34\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#95d8e0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Y52-Yellow\",\n          \"colors\": [\"#e8ea7c\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ef332d\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#73479a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#f097c0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light green\",\n          \"colors\": [\"#39b773\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#1857a7\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#e6e74d\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#a65a9d\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [17, 92],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Gobo\"\n        },\n        {\n          \"dmxRange\": [93, 136],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Color\"\n        },\n        {\n          \"dmxRange\": [137, 196],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Gobo + Color\"\n        },\n        {\n          \"dmxRange\": [197, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [12, 22],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [23, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [34, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [45, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [56, 66],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [67, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [78, 88],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [89, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [100, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [111, 121],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [122, 128],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Tilt\": {\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"60deg\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Default\",\n      \"channels\": [\n        \"Shutter\",\n        \"Gobo Wheel\",\n        \"Color Wheel\",\n        \"Pan\",\n        \"Tilt\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/orion/orcan2.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ORCAN2\",\n  \"shortName\": \"OrionOrcan2\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-04-04\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://orion-fxlights.com/downloads/ownersman/om_orcan2.pdf?v=1427215602\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [255, 365, 255],\n    \"weight\": 2.8,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"36 x 3W RGB LEDs (12 x Red / 12 x Green / 12 x Blue)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color pulse\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Effects\",\n        \"Effect Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/panasonic/pt-rz120.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PT-RZ120\",\n  \"categories\": [\"Other\", \"Laser\"],\n  \"meta\": {\n    \"authors\": [\"Walter Ponce\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-04-03\",\n    \"lastModifyDate\": \"2020-04-03\"\n  },\n  \"comment\": \"Single Chip Laser 12k Projector\",\n  \"links\": {\n    \"manual\": [\n      \"https://eww.pavc.panasonic.co.jp/projector/extranet/main/products/rz120/manual.html\"\n    ],\n    \"productPage\": [\n      \"https://panasonic.net/cns/projector/products/rz120/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2DrfjBJxjYA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [498, 200, 581],\n    \"weight\": 23.6,\n    \"power\": 1100,\n    \"bulb\": {\n      \"type\": \"Laser Diode\",\n      \"lumens\": 12000\n    }\n  },\n  \"availableChannels\": {\n    \"Light Output\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"bright\",\n        \"brightnessEnd\": \"off\"\n      }\n    },\n    \"Input Select (1)\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DVI-D\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"HDMI\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Digital Link\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"SDI\"\n        },\n        {\n          \"dmxRange\": [64, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Input Select (2 / User)\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DVI-D\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"HDMI\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Digital Link\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"SDI\"\n        },\n        {\n          \"dmxRange\": [56, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Lens Position\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Move to home position\"\n        },\n        {\n          \"dmxRange\": [64, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Lens H Shift\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Speed\",\n          \"speed\": \"1%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Speed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment +\"\n        }\n      ]\n    },\n    \"Lens V Shift\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Speed\",\n          \"speed\": \"1%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Speed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment +\"\n        }\n      ]\n    },\n    \"Lens Focus\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Speed\",\n          \"speed\": \"1%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Speed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment +\"\n        }\n      ]\n    },\n    \"Lens Zoom\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Speed\",\n          \"speed\": \"1%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Speed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment +\"\n        }\n      ]\n    },\n    \"Lens Function Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lens H Shift\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lens V Shift\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lens Focus\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lens Zoom\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Move to home position\"\n        },\n        {\n          \"dmxRange\": [96, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Lens Control\": {\n      \"defaultValue\": 100,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Speed\",\n          \"speed\": \"1%\",\n          \"comment\": \"Lens adjustment –\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Speed\",\n          \"speed\": \"slow\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Speed\",\n          \"speed\": \"50%\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Speed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Lens adjustment +\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Execute command action\"\n        }\n      ]\n    },\n    \"Power\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standby\"\n        },\n        {\n          \"dmxRange\": [64, 191],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Power on\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 191],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        }\n      ]\n    },\n    \"Fade in\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"0.5s\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"1s\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"1.5s\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"2s\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"2.5s\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"3s\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"3.5s\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"4s\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"5s\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"7s\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"10s\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Fade out\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"0.5s\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"1s\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"1.5s\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"2s\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"2.5s\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"3s\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"3.5s\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"4s\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"5s\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"7s\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"10s\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Geometry\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Keystone\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Curved correction\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-1\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-2\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-3\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Corner correction\"\n        },\n        {\n          \"dmxRange\": [112, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Custom Masking\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-1\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-2\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-3\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Freeze\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"off\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [160, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"on\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Factory default setting\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": -31,\n          \"parameterEnd\": -1\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Maintenance\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [130, 191],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 1,\n          \"parameterEnd\": 31\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Factory default setting\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": -31,\n          \"parameterEnd\": -1\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Maintenance\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [130, 191],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 1,\n          \"parameterEnd\": 31\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Raster Pattern\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"white\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"yellow\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"cyan\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"green\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"magenta\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"red\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"blue\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"black\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"User logo\"\n        },\n        {\n          \"dmxRange\": [176, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Enable/Disable\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1\",\n      \"channels\": [\n        \"Shutter\",\n        \"Input Select (1)\",\n        \"Lens Function Select\",\n        \"Lens Control\",\n        \"Power\",\n        \"Light Output\",\n        \"Enable/Disable\",\n        \"Fade in\",\n        \"Fade out\",\n        \"Custom Masking\",\n        \"Geometry\"\n      ]\n    },\n    {\n      \"name\": \"2\",\n      \"channels\": [\n        \"Light Output\",\n        \"Input Select (2 / User)\",\n        \"Lens Position\",\n        \"Lens H Shift\",\n        \"Lens V Shift\",\n        \"Lens Focus\",\n        \"Lens Zoom\",\n        \"Power\",\n        \"Geometry\",\n        \"Custom Masking\",\n        \"Enable/Disable\"\n      ]\n    },\n    {\n      \"name\": \"Additional user channels\",\n      \"channels\": [\n        \"Freeze\",\n        \"Color\",\n        \"Tint\",\n        \"Raster Pattern\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/panasonic/pt-rz120l.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PT-RZ120L\",\n  \"categories\": [\"Other\", \"Laser\"],\n  \"meta\": {\n    \"authors\": [\"Walter Ponce\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-03-30\",\n    \"lastModifyDate\": \"2020-03-30\"\n  },\n  \"comment\": \"Single Chip Laser 12k Projector\",\n  \"links\": {\n    \"manual\": [\n      \"https://eww.pavc.panasonic.co.jp/projector/extranet/main/products/rz120/manual.html\"\n    ],\n    \"productPage\": [\n      \"https://panasonic.net/cns/projector/products/rz120/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2DrfjBJxjYA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [498, 200, 538],\n    \"weight\": 22.8,\n    \"power\": 1100,\n    \"bulb\": {\n      \"type\": \"Laser Diode\",\n      \"lumens\": 12000\n    }\n  },\n  \"availableChannels\": {\n    \"Light Output\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Input Select (1)\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DVI-D\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"HDMI\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Digital Link\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"SDI\"\n        },\n        {\n          \"dmxRange\": [64, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Input Select (2 / User)\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DVI-D\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"HDMI\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Digital Link\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"SDI\"\n        },\n        {\n          \"dmxRange\": [56, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Lens Position\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Move to home position\"\n        },\n        {\n          \"dmxRange\": [64, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Lens H Shift\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-100%\",\n          \"parameterEnd\": \"-50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-50%\",\n          \"parameterEnd\": \"-1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-1%\",\n          \"parameterEnd\": \"-0.1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"EffectParameter\",\n          \"parameter\": \"0%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"0.1%\",\n          \"parameterEnd\": \"1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"1%\",\n          \"parameterEnd\": \"50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"50%\",\n          \"parameterEnd\": \"100%\",\n          \"comment\": \"Lens adjustment\"\n        }\n      ]\n    },\n    \"Lens V Shift\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-100%\",\n          \"parameterEnd\": \"-50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-50%\",\n          \"parameterEnd\": \"-1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-1%\",\n          \"parameterEnd\": \"-0.1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"EffectParameter\",\n          \"parameter\": \"0%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"0.1%\",\n          \"parameterEnd\": \"1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"1%\",\n          \"parameterEnd\": \"50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"50%\",\n          \"parameterEnd\": \"100%\",\n          \"comment\": \"Lens adjustment\"\n        }\n      ]\n    },\n    \"Lens Focus\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-100%\",\n          \"parameterEnd\": \"-50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-50%\",\n          \"parameterEnd\": \"-1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-1%\",\n          \"parameterEnd\": \"-0.1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"EffectParameter\",\n          \"parameter\": \"0%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"0.1%\",\n          \"parameterEnd\": \"1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"1%\",\n          \"parameterEnd\": \"50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"50%\",\n          \"parameterEnd\": \"100%\",\n          \"comment\": \"Lens adjustment\"\n        }\n      ]\n    },\n    \"Lens Zoom\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-100%\",\n          \"parameterEnd\": \"-50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-50%\",\n          \"parameterEnd\": \"-1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-1%\",\n          \"parameterEnd\": \"-0.1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"EffectParameter\",\n          \"parameter\": \"0%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"0.1%\",\n          \"parameterEnd\": \"1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"1%\",\n          \"parameterEnd\": \"50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"50%\",\n          \"parameterEnd\": \"100%\",\n          \"comment\": \"Lens adjustment\"\n        }\n      ]\n    },\n    \"Lens Function Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lens H Shift\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lens V Shift\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lens Focus\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lens Zoom\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Move to home position\"\n        },\n        {\n          \"dmxRange\": [96, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Lens Control\": {\n      \"defaultValue\": 100,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-100%\",\n          \"parameterEnd\": \"-50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-50%\",\n          \"parameterEnd\": \"-1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"-1%\",\n          \"parameterEnd\": \"-0.1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"EffectParameter\",\n          \"parameter\": \"0%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"0.1%\",\n          \"parameterEnd\": \"1%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"1%\",\n          \"parameterEnd\": \"50%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"50%\",\n          \"parameterEnd\": \"100%\",\n          \"comment\": \"Lens adjustment\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Execute command action\"\n        }\n      ]\n    },\n    \"Power\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standby\"\n        },\n        {\n          \"dmxRange\": [64, 191],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Power on\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 191],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        }\n      ]\n    },\n    \"Fade in\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"0.5s\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"1s\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"1.5s\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"2s\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"2.5s\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"3s\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"3.5s\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"4s\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"5s\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"7s\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"10s\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Fade out\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"instant\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"0.5s\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"1s\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"1.5s\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"2s\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"2.5s\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"3s\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"3.5s\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"4s\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"5s\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"7s\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"EffectDuration\",\n          \"duration\": \"10s\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Geometry\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Keystone\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Curved correction\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-1\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-2\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-3\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Corner correction\"\n        },\n        {\n          \"dmxRange\": [112, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Custom Masking\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-1\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-2\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PC-3\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Freeze\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"off\"\n        },\n        {\n          \"dmxRange\": [96, 159],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [160, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"off\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Factory default setting\"\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"Maintenance\",\n          \"parameter\": -31\n        },\n        {\n          \"dmxRange\": [66, 127],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": -30,\n          \"parameterEnd\": -1\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Maintenance\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 1,\n          \"parameterEnd\": 30\n        },\n        {\n          \"dmxRange\": [190, 191],\n          \"type\": \"Maintenance\",\n          \"parameter\": 31\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Tint\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Factory default setting\"\n        },\n        {\n          \"dmxRange\": [64, 65],\n          \"type\": \"Maintenance\",\n          \"parameter\": -31\n        },\n        {\n          \"dmxRange\": [66, 127],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": -30,\n          \"parameterEnd\": -1\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Maintenance\",\n          \"parameter\": 0\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Maintenance\",\n          \"parameterStart\": 1,\n          \"parameterEnd\": 30\n        },\n        {\n          \"dmxRange\": [190, 191],\n          \"type\": \"Maintenance\",\n          \"parameter\": 31\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Raster Pattern\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"off\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"white\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"yellow\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"cyan\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"green\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"magenta\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"red\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"blue\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"black\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"User logo\"\n        },\n        {\n          \"dmxRange\": [176, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Enable/Disable\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1\",\n      \"channels\": [\n        \"Shutter\",\n        \"Input Select (1)\",\n        \"Lens Function Select\",\n        \"Lens Control\",\n        \"Power\",\n        \"Light Output\",\n        \"Enable/Disable\",\n        \"Fade in\",\n        \"Fade out\",\n        \"Custom Masking\",\n        \"Geometry\"\n      ]\n    },\n    {\n      \"name\": \"2\",\n      \"channels\": [\n        \"Light Output\",\n        \"Input Select (2 / User)\",\n        \"Lens Position\",\n        \"Lens H Shift\",\n        \"Lens V Shift\",\n        \"Lens Focus\",\n        \"Lens Zoom\",\n        \"Power\",\n        \"Geometry\",\n        \"Custom Masking\",\n        \"Enable/Disable\"\n      ]\n    },\n    {\n      \"name\": \"Additional user channels\",\n      \"channels\": [\n        \"Freeze\",\n        \"Color\",\n        \"Tint\",\n        \"Raster Pattern\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/phocea-light/box-leds-batterie-6x15w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Box LEDs Batterie 6x15W\",\n  \"shortName\": \"PL-BOXBHF6X15W\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"STUDIO5\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-03-24\",\n    \"lastModifyDate\": \"2020-03-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.phocealight.fr/index.php?controller=attachment&id_attachment=6\"\n    ],\n    \"productPage\": [\n      \"https://www.phocealight.fr/pars-leds-batterie/25-77-box-batterie-6x15w.html#/30-couleur-noir\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=RMeX3Y-FwzA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [170, 230, 170],\n    \"weight\": 2.4,\n    \"power\": 110,\n    \"bulb\": {\n      \"type\": \"6× 15W RGBWA+UV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 35]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color / Program Speed\": \"Color\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color selection\",\n          \"switchChannels\": {\n            \"Color / Program Speed\": \"Color\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"What does happen in this DMX range?\",\n          \"switchChannels\": {\n            \"Color / Program Speed\": \"Color\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 169],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"What does happen in this DMX range?\",\n          \"switchChannels\": {\n            \"Color / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 209],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound pulse + strobe\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound strobe\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color / Program Speed\": \"Program Speed\"\n          }\n        }\n      ]\n    },\n    \"Color\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Mode\",\n        \"Color / Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/powerlighting/wash-84w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Wash 84W\",\n  \"shortName\": \"wash84w\",\n  \"categories\": [\"Color Changer\", \"Moving Head\"],\n  \"meta\": {\n    \"authors\": [\"Millumin\", \"CypGit\"],\n    \"createDate\": \"2018-04-04\",\n    \"lastModifyDate\": \"2019-05-17\"\n  },\n  \"comment\": \"There exist different variants of this fixture. Most retailers only state 13 channels, but there's also a manual with 9/14 channel modes. The physical data is also inconsistent.\",\n  \"links\": {\n    \"other\": [\n      \"https://github.com/OpenLightingProject/open-fixture-library/pull/461\",\n      \"https://github.com/OpenLightingProject/open-fixture-library/issues/792\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [177, 230, 177],\n    \"weight\": 2.7,\n    \"power\": 90,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\",\n        \"helpWanted\": \"Is 270° the correct tilt maximum for all fixture variants?\"\n      }\n    },\n    \"Movement Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 134],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [135, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"40Hz\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"RGBW Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"static\",\n          \"helpWanted\": \"Is this a single color? At which DMX value can which colors be selected?\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 94],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"cut\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"smooth\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [155, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"soft\",\n          \"helpWanted\": \"Where is the difference to 'smooth'?\"\n        }\n      ]\n    },\n    \"RGBW Presets / Chase\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectPreset\": \"ColorFade\",\n        \"helpWanted\": \"At which DMX values can which colors be selected and at which DMX values is the chase effect active?\"\n      }\n    },\n    \"Chase Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [7, 65],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [66, 69],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"Or Shutter Open / Closed?\"\n        },\n        {\n          \"dmxRange\": [70, 128],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [129, 132],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [133, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [196, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        }\n      ]\n    },\n    \"Music control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"high\"\n        }\n      ]\n    },\n    \"Sound Effects\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Music controlled programs\",\n        \"helpWanted\": \"How many programs are there and at which DMX values can you select them?\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"helpWanted\": \"Does one need to hold this capability for a certain amount of seconds?\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Movement Speed\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"RGBW Presets\",\n        \"Strobe\",\n        \"Music control\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Dimmer / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"RGBW Presets / Chase\",\n        \"Chase Speed\",\n        \"Sound Effects\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/pr-lighting/xs-250-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"XS 250 Spot\",\n  \"shortName\": \"PR-XS250\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"SEB\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-03-29\",\n    \"lastModifyDate\": \"2019-03-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.thedmxwiki.com/_media/lighting_fixtures/pr_lighting/pr_lighting_xs_250.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [390, 564, 373],\n    \"weight\": 22,\n    \"power\": 370,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Philips MSD 250W/2\",\n      \"colorTemperature\": 8500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [16, 16]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    },\n    \"Fixed Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 25],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"helpWanted\": \"Does this capability start at 10 or 11?\"\n        },\n        {\n          \"dmxRange\": [26, 225],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"12Hz\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [21, 28],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"helpWanted\": \"What colors can be chosen?\"\n        },\n        {\n          \"dmxRange\": [29, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [46, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [55, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [63, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [72, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [81, 88],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [89, 97],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [98, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [106, 114],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [115, 123],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 187],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [188, 195],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [196, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Fixed Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"helpWanted\": \"What gobos can be chosen?\"\n        },\n        {\n          \"dmxRange\": [24, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [35, 46],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [47, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [58, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [70, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [81, 92],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [93, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [104, 115],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [116, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [128, 150],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [151, 171],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [172, 183],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [17, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"helpWanted\": \"What gobos can be chosen?\"\n        },\n        {\n          \"dmxRange\": [33, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [49, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [65, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [81, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [97, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 150],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [151, 171],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [172, 183],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [184, 195],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [196, 207],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [208, 219],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [220, 231],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [232, 243],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [244, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"fineChannelAliases\": [\"Gobo Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"540deg\"\n        },\n        {\n          \"dmxRange\": [128, 188],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [189, 194],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [195, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 136],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [137, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 48],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [49, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [81, 112],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [113, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\",\n          \"hold\": \"10s\"\n        },\n        {\n          \"dmxRange\": [145, 168],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [169, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp power reduced to 50%\"\n        },\n        {\n          \"dmxRange\": [201, 223],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"STd\",\n      \"channels\": [\n        \"Strobe\",\n        \"Dimmer\",\n        \"Color Wheel\",\n        \"Fixed Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Extended\",\n      \"shortName\": \"EXT\",\n      \"channels\": [\n        \"Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Color Wheel\",\n        \"Fixed Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Gobo Rotation fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Short\",\n      \"shortName\": \"SHRT\",\n      \"channels\": [\n        \"Strobe\",\n        \"Dimmer\",\n        \"Color Wheel\",\n        \"Fixed Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Pan\",\n        \"Tilt\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/prolights/diamond19.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DIAMOND19\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"fueller\", \"ameisso\", \"Ryan Goodwin\"],\n    \"createDate\": \"2017-08-16\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.musiclights.it/download.php?id=3932\"\n    ],\n    \"productPage\": [\n      \"https://www.prolights.it/product/DIAMOND19BK\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=F5nu7TYshPA\",\n      \"https://www.youtube.com/watch?v=WFtywtM_Kqg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [338, 449, 235],\n    \"weight\": 11,\n    \"power\": 316,\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"name\": \"Honey-Comb gapless plano convex optics\",\n      \"degreesMinMax\": [6, 66]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null, null, null, \"10\", null, \"11\", null, null, null],\n        [null,  \"9\", null, null, null, null, null, \"12\", null],\n        [null, null, null, null,  \"3\", null, null, null, null],\n        [ \"8\", null,  \"2\", null,  null, null, \"4\", null, \"13\"],\n        [null, null, null,  null, \"1\", null, null, null, null],\n        [\"19\", null,  \"7\", null,  null, null, \"5\", null, \"14\"],\n        [null, null, null, null,  \"6\", null, null, null, null],\n        [null, \"18\", null, null, null, null, null, \"15\", null],\n        [null, null, null, \"17\", null, \"16\", null, null, null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Center\": [\"1\"],\n      \"Middle ring\": { \"name\": [\"^[2-7]$\"] },\n      \"Outer ring\": { \"name\": [\"^(8|9|1\\\\d)$\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"265deg\"\n      }\n    },\n    \"Movement Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Movement Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal Movement Functions\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Movement with Blackout\"\n        },\n        {\n          \"dmxRange\": [32, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Forward\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"Reverse\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [64, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Shutter Extended\": {\n      \"name\": \"Shutter\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 223],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Shutter Basic\": {\n      \"name\": \"Shutter\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Virtual Color Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"On Function\",\n          \"switchChannels\": {\n            \"Virtual Color 1\": \"Color Function\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CTC Function\",\n          \"switchChannels\": {\n            \"Virtual Color 1\": \"CTC Function\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Forward Spin\",\n          \"switchChannels\": {\n            \"Virtual Color 1\": \"Rainbow Effect Forward\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reverse Spin\",\n          \"switchChannels\": {\n            \"Virtual Color 1\": \"Rainbow Effect Reverse\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Continuous\",\n          \"switchChannels\": {\n            \"Virtual Color 1\": \"Color Function\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Bounce\",\n          \"switchChannels\": {\n            \"Virtual Color 1\": \"Color Function\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 255],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Virtual Color 1\": \"Color Function\"\n          }\n        }\n      ]\n    },\n    \"Rainbow Effect Forward\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Rainbow Effect Reverse\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow reverse\",\n        \"speedEnd\": \"fast reverse\"\n      }\n    },\n    \"CTC Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 223],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2000K\",\n          \"colorTemperatureEnd\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        }\n      ]\n    },\n    \"Color Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Black\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [5, 46],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#00ffff\"],\n          \"comment\": \"Green ASC, Blue\"\n        },\n        {\n          \"dmxRange\": [47, 88],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"Green, Blue DESC\"\n        },\n        {\n          \"dmxRange\": [89, 130],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#ffff00\"],\n          \"comment\": \"Red ASC, Green\"\n        },\n        {\n          \"dmxRange\": [131, 172],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#ff0000\"],\n          \"comment\": \"Red, Green DESC\"\n        },\n        {\n          \"dmxRange\": [173, 214],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ff00ff\"],\n          \"comment\": \"Red, Blue ASC\"\n        },\n        {\n          \"dmxRange\": [215, 255],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Red DESC, Blue\"\n        }\n      ]\n    },\n    \"Virtual Color 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Black\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [5, 46],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#00ffff\"],\n          \"comment\": \"Green ASC, Blue\"\n        },\n        {\n          \"dmxRange\": [47, 88],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"Green, Blue DESC\"\n        },\n        {\n          \"dmxRange\": [89, 130],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#ffff00\"],\n          \"comment\": \"Red ASC, Green\"\n        },\n        {\n          \"dmxRange\": [131, 172],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#ff0000\"],\n          \"comment\": \"Red, Green DESC\"\n        },\n        {\n          \"dmxRange\": [173, 214],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ff00ff\"],\n          \"comment\": \"Red, Blue ASC\"\n        },\n        {\n          \"dmxRange\": [215, 255],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Red DESC, Blue\"\n        }\n      ]\n    },\n    \"Red-All\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green-All\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue-All\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White-All\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Foreground\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Color\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Full Color\"\n        }\n      ]\n    },\n    \"Background\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No Color\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Full Color\"\n        }\n      ]\n    },\n    \"Patterns\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static Pattern\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Static Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 1\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 2\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 3\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 4\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 5\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 6\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 7\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 8\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 9\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 10\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 11\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 12\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 13\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dynamic Pattern 14\",\n          \"switchChannels\": {\n            \"Pattern Speed\": \"Dynamic Pattern Speed\"\n          }\n        }\n      ]\n    },\n    \"Static Pattern Speed\": {\n      \"defaultValue\": 127,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dynamic Pattern Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [4, 127],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [132, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Pattern Byte 1\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED1 and LED2 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 2\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED3 and LED4 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 3\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED5 and LED6 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 4\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED7 and LED8 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 5\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED9 and LED10 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 6\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED11 and LED12 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 7\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED13 and LED14 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 8\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED15 and LED16 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 9\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED17 and LED18 RGBW flags\"\n      }\n    },\n    \"Pattern Byte 10\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Bit access to LED19 RGBW flags\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Normal\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset All\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan&Tilt Reset\"\n        },\n        {\n          \"dmxRange\": [24, 47],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Other Reset\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display Off\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display On\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Hibernation\"\n        },\n        {\n          \"dmxRange\": [96, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Movement Speed\",\n        \"Shutter Function\",\n        \"Shutter Extended\",\n        \"Dimmer\",\n        \"Virtual Color Function\",\n        \"Virtual Color 1\",\n        \"Virtual Color 2\",\n        \"Red-All\",\n        \"Green-All\",\n        \"Blue-All\",\n        \"White-All\",\n        \"Zoom\",\n        \"Foreground\",\n        \"Background\",\n        \"Patterns\",\n        \"Pattern Speed\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Basic 8-bit\",\n      \"shortName\": \"bas8\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Movement Speed\",\n        \"Shutter Basic\",\n        \"Dimmer\",\n        \"Virtual Color Function\",\n        \"Virtual Color 1\",\n        \"Virtual Color 2\",\n        \"Red-All\",\n        \"Green-All\",\n        \"Blue-All\",\n        \"White-All\",\n        \"Zoom\",\n        \"Foreground\",\n        \"Background\",\n        \"Patterns\",\n        \"Pattern Speed\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Basic 16-bit\",\n      \"shortName\": \"bas16\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Shutter Basic\",\n        \"Dimmer\",\n        \"Virtual Color Function\",\n        \"Virtual Color 1\",\n        \"Virtual Color 2\",\n        \"Red-All\",\n        \"Green-All\",\n        \"Blue-All\",\n        \"White-All\",\n        \"Zoom\",\n        \"Foreground\",\n        \"Background\",\n        \"Patterns\",\n        \"Pattern Speed\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Extended 1\",\n      \"shortName\": \"ext1\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Movement Function\",\n        \"Shutter Function\",\n        \"Shutter Extended\",\n        \"Dimmer\",\n        \"Virtual Color Function\",\n        \"Virtual Color 1\",\n        \"Virtual Color 2\",\n        \"Red-All\",\n        \"Green-All\",\n        \"Blue-All\",\n        \"White-All\",\n        \"Zoom\",\n        \"Foreground\",\n        \"Background\",\n        \"Patterns\",\n        \"Pattern Speed\",\n        \"Pattern Byte 1\",\n        \"Pattern Byte 2\",\n        \"Pattern Byte 3\",\n        \"Pattern Byte 4\",\n        \"Pattern Byte 5\",\n        \"Pattern Byte 6\",\n        \"Pattern Byte 7\",\n        \"Pattern Byte 8\",\n        \"Pattern Byte 9\",\n        \"Pattern Byte 10\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Extended 2\",\n      \"shortName\": \"ext2\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Movement Speed\",\n        \"Movement Function\",\n        \"Shutter Function\",\n        \"Shutter Extended\",\n        \"Dimmer\",\n        \"Virtual Color Function\",\n        \"Virtual Color 1\",\n        \"Virtual Color 2\",\n        \"Red-All\",\n        \"Green-All\",\n        \"Blue-All\",\n        \"White-All\",\n        \"Zoom\",\n        \"Foreground\",\n        \"Background\",\n        \"Patterns\",\n        \"Pattern Speed\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/prolights/pixpan16.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PIXPAN16\",\n  \"categories\": [\"Matrix\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-02\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.musiclights.it/download.php?id=2249\"\n    ],\n    \"productPage\": [\n      \"https://www.prolights.it/product/PIXPAN16\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=0hAYNFjOEsQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [460, 460, 120],\n    \"weight\": 8,\n    \"power\": 390,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"4x4 30W RGBW/FC COB-LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [60, 60]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 4, 1]\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter Extended\": {\n      \"name\": \"Shutter\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Auto Show\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Chase\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 5\"\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 6\"\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 7\"\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 8\"\n        },\n        {\n          \"dmxRange\": [171, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 9\"\n        },\n        {\n          \"dmxRange\": [191, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 10\"\n        },\n        {\n          \"dmxRange\": [211, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 11\"\n        },\n        {\n          \"dmxRange\": [231, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 12\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random auto show (1-12)\"\n        }\n      ]\n    },\n    \"Shutter Simple\": {\n      \"name\": \"Shutter\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\",\n        \"Shutter Extended\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Shutter Simple\",\n        \"Chase\",\n        \"Speed\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"48-channel\",\n      \"shortName\": \"48ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/prolights/polar3000.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"POLAR3000\",\n  \"shortName\": \"PLPolar3000\",\n  \"categories\": [\"Strobe\", \"Blinder\"],\n  \"meta\": {\n    \"authors\": [\"TAP\"],\n    \"createDate\": \"2019-02-16\",\n    \"lastModifyDate\": \"2019-02-16\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.musiclights.it/download.php?id=2545\"\n    ],\n    \"productPage\": [\n      \"https://www.musiclights.it/product/POLAR3000?lang=EN\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [455, 221, 80],\n    \"weight\": 4.5,\n    \"power\": 462,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"882x0.5W SMD LEDs\",\n      \"colorTemperature\": 6500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [62, 151, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [6, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 1\"\n        },\n        {\n          \"dmxRange\": [41, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 2\"\n        },\n        {\n          \"dmxRange\": [71, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 3\"\n        },\n        {\n          \"dmxRange\": [101, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 4\"\n        },\n        {\n          \"dmxRange\": [131, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 5\"\n        },\n        {\n          \"dmxRange\": [161, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 6\"\n        },\n        {\n          \"dmxRange\": [191, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 7\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 0\"\n        }\n      ]\n    },\n    \"Auto Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Menu setting dimmer mode\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer mode off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer mode 1\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer mode 2\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer mode 3\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe\",\n        \"Dimmer Mode\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Strobe\",\n        \"Auto Programs\",\n        \"Auto Speed\",\n        \"Dimmer Mode\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\"\n          ]\n        },\n        \"Auto Programs\",\n        \"Auto Speed\",\n        \"Dimmer Master\",\n        \"Strobe\",\n        \"Dimmer Mode\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/prolights/smartbat.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SMARTBAT\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Matteo Piccina\"],\n    \"createDate\": \"2019-12-23\",\n    \"lastModifyDate\": \"2019-12-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.musiclights.it/download.php?id=3844\"\n    ],\n    \"productPage\": [\n      \"https://www.musiclights.it/product/SMARTBAT\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2A7gp6_6tMQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [137.8, 184, 145],\n    \"weight\": 3.4,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4× 8W RGBW LED\",\n      \"lumens\": 1127\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Presets / Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"warm\",\n          \"colorTemperatureEnd\": \"cold\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Auto/Sound Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [61, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [121, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [181, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Show\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Auto Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use device setting\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-Channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"10-Channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Presets / Temperature\",\n        \"Strobe\",\n        \"Auto/Sound Programs\",\n        \"Auto Speed\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/prolights/v700spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"V700SPOT\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Lorenzo Andreani\"],\n    \"createDate\": \"2018-11-01\",\n    \"lastModifyDate\": \"2018-11-01\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-11-01\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.2)\"\n    }\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.musiclights.it/product/V700SPOT\"\n    ],\n    \"other\": [\n      \"https://personalities.avolites.com/?mainPage=ViewPersonality.aspx&FileID=27856\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [465, 685, 465],\n    \"weight\": 32.6,\n    \"power\": 850,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"MSR 700W\",\n      \"colorTemperature\": 7500,\n      \"lumens\": 56000\n    },\n    \"lens\": {\n      \"name\": \"PC\",\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#add8e6\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV Purple\",\n          \"colors\": [\"#e005fa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#90ee90\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"3200K\",\n          \"colors\": [\"#ffc076\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"5600K\",\n          \"colors\": [\"#ffefe1\"]\n        }\n      ]\n    },\n    \"Color Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffa500\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Yellow\",\n          \"colors\": [\"#ffffe0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Gobo Shake\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 185],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [186, 239],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [19, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [28, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [46, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [55, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Color Wheel 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [19, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [28, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [37, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [46, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [55, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"WheelRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 167],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [168, 207],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [22, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [43, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [64, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [85, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [106, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1 Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [22, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [43, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [64, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [85, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [106, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"No Function\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Prism\"\n        },\n        {\n          \"dmxRange\": [16, 39],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [40, 63],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [64, 87],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [88, 111],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [112, 135],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [136, 159],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [160, 183],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [184, 207],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [208, 231],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 10\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"PrismRotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Iris\": {\n      \"capability\": {\n        \"type\": \"Iris\",\n        \"openPercentStart\": \"open\",\n        \"openPercentEnd\": \"closed\"\n      }\n    },\n    \"Reset / Lamp Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable Blackout during Pan/Tilt Move\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable Blackout during Pan/Tilt Move\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable Blackout during Color 1 / Color 2 Change\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable Blackout during Color 1 / Color 2 Change\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable Blackout during Gobo 1 / Gobo 2 Change\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable Blackout during Gobo 1 / Gobo 2 Change\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp On\"\n        },\n        {\n          \"dmxRange\": [140, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX Reset\"\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp Off\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 28\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 29\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 30\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 31\"\n        }\n      ]\n    },\n    \"Pan/Tilt Movement Size\": {\n      \"capability\": {\n        \"type\": \"EffectParameter\",\n        \"parameterStart\": \"small\",\n        \"parameterEnd\": \"big\",\n        \"helpWanted\": \"Is it small…big or big…small?\"\n      }\n    },\n    \"Iris Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 90],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"RampDown\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [91, 172],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"RampUp\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [173, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Pulse\",\n          \"speed\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [132, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"22-channel\",\n      \"shortName\": \"22ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Gobo Shake\",\n        \"Color Wheel 1\",\n        \"Color Wheel 2\",\n        \"Gobo Wheel 1\",\n        \"Gobo Wheel 1 Rotation\",\n        \"Gobo Wheel 2\",\n        \"No Function\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Iris\",\n        \"Reset / Lamp Control\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Macros\",\n        \"Pan/Tilt Movement Size\",\n        \"Iris Effect\",\n        \"Dimmer Effect\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Gobo Shake\",\n        \"Color Wheel 1\",\n        \"Color Wheel 2\",\n        \"Gobo Wheel 1\",\n        \"Gobo Wheel 1 Rotation\",\n        \"Gobo Wheel 2\",\n        \"No Function\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Focus\",\n        \"Iris\",\n        \"Reset / Lamp Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/qtx/lux-ld01.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Lux Ld01\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Thomaxz\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-11-01\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/752487/Qtx-Lux-Ld01.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=EKwxFZwRC3M\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [173, 249, 173],\n    \"weight\": 3.8,\n    \"power\": 83.6,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"14W RGB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Flower\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Light Swirl\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Triangle Circle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Small Hearts\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Small lights\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Star like\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Big swirl\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Lines in quads\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Flowers\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 134],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"100%\",\n          \"brightnessEnd\": \"0%\"\n        },\n        {\n          \"dmxRange\": [135, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [22, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [35, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [50, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [64, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [78, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [92, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#cc00ff\"]\n        },\n        {\n          \"dmxRange\": [120, 133],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [134, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chartreuse\",\n          \"colors\": [\"#7fff00\"]\n        },\n        {\n          \"dmxRange\": [148, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff66cc\"]\n        },\n        {\n          \"dmxRange\": [162, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Brown\",\n          \"colors\": [\"#aa6600\"]\n        },\n        {\n          \"dmxRange\": [176, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold\",\n          \"colors\": [\"#ffcc00\"]\n        },\n        {\n          \"dmxRange\": [190, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Crimson\",\n          \"colors\": [\"#dc143c\"]\n        },\n        {\n          \"dmxRange\": [204, 217],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Violet\",\n          \"colors\": [\"#6600ff\"]\n        },\n        {\n          \"dmxRange\": [218, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Crape\",\n          \"colors\": [\"#ff66aa\"]\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        }\n      ]\n    },\n    \"Vector Speed (Color)\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Movement Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [23, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [38, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [53, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\"\n        },\n        {\n          \"dmxRange\": [68, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 5\"\n        },\n        {\n          \"dmxRange\": [83, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 6\"\n        },\n        {\n          \"dmxRange\": [98, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 7\"\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 8\"\n        },\n        {\n          \"dmxRange\": [128, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [143, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [158, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [173, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [188, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [203, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [218, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [233, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active Program 8\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [80, 94],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [95, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [110, 124],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [125, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [140, 154],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [155, 169],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [170, 184],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [185, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [200, 214],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [215, 235],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"13-Channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Vector Speed (Color)\",\n        \"Movement Macros\",\n        \"Gobo Wheel\"\n      ]\n    },\n    {\n      \"name\": \"12-Channel for Wash\",\n      \"shortName\": \"12ch-wash\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Vector Speed (Color)\",\n        \"Movement Macros\"\n      ]\n    },\n    {\n      \"name\": \"5-Channel for Spot\",\n      \"shortName\": \"5ch-spot\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer / Strobe\",\n        \"Color Macros\",\n        \"Gobo Wheel\"\n      ]\n    },\n    {\n      \"name\": \"4-Channel for Wash\",\n      \"shortName\": \"4ch-wash\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer / Strobe\",\n        \"Color Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/qtx/lux-ld30w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LUX-LD30W\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Nerijus Mongirdas\", \"Flo Edelmann\"],\n    \"createDate\": \"2017-09-19\",\n    \"lastModifyDate\": \"2018-09-04\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2017-09-19\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.0)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.discoworld.dk/manuals/avsl/150447.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [345, 435, 340],\n    \"weight\": 6.8,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"1x 30W White LED\",\n      \"lumens\": 265\n    },\n    \"lens\": {\n      \"degreesMinMax\": [12, 12]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7700\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ff00aa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [18, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [34, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [51, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [68, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [85, 101],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [102, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [108, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 192],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [21, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [42, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [63, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [84, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [128, 192],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Dimmer / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [1, 115],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"off\",\n          \"brightnessEnd\": \"bright\"\n        },\n        {\n          \"dmxRange\": [116, 243],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [244, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Electronic reset\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo rotation\",\n        \"Dimmer / Strobe\",\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/renkforce/gm107.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"GM107\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Edgar Aichinger\"],\n    \"createDate\": \"2018-09-13\",\n    \"lastModifyDate\": \"2018-09-13\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-09-13\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.1 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://asset.conrad.com/media10/add/160267/c1/-/gl/001368692ML02/bedienungsanleitung-1368692-renkforce-1368692-gm107-led-moving-head-anzahl-leds-details7-x-10-w.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.amazon.co.uk/1374784-RENKFORCE-GM107-LED-MOVING-HEAD-15/dp/B01AIBNB0Q\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=tshDiXa8DkE\"\n    ],\n    \"other\": [\n      \"https://github.com/OpenLightingProject/open-fixture-library/pull/612\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 243, 180],\n    \"weight\": 2.65,\n    \"power\": 70,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 4500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Pan/Tilt speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Strobe effect\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual control\"\n        },\n        {\n          \"dmxRange\": [1, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [85, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mode\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [170, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound to light\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    },\n    \"Color mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Color intensity channels active\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rainbow Effect\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Color selection\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"comment\": \"Rainbow Effect\",\n        \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt speed\",\n        \"Strobe effect\",\n        \"Color selection\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt speed\",\n        \"Strobe effect\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color mode\",\n        \"Program\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/colorspot-2500e-at.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ColorSpot 2500E AT\",\n  \"shortName\": \"robeSpot2500\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"novasfronteiras.co\"],\n    \"createDate\": \"2017-09-07\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/api/support-files/download/downloads/user_manuals/User_manual_ColorSpot_2500E_AT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/colorspot-2500e-at\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 7\n  },\n  \"physical\": {\n    \"dimensions\": [536, 638, 678],\n    \"weight\": 42.5,\n    \"power\": 1760,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Philips MSR GOLD 1200 FastFit\",\n      \"colorTemperature\": 6300\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 30]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep Red\",\n          \"colors\": [\"#dd0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep Blue\",\n          \"colors\": [\"#0000dd\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff9900\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#fff6ed\"],\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV Filter\",\n          \"colors\": [\"#8800ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Rainbow Chips 15030012\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Sun Man 15030013\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Water Drops 15030014\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Triangle Floating 15020123\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Laser 15020124\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Swirl Electric 15020125\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Diamante Spot 15040020\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Wheel 15020126\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Space Tunel 15020127\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bubbles 1 15020128\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"12 Dots 15020129\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Radial Dashes 15020130\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"530deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"260deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Power/Special functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"reserved\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"autofocus on\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"autofocus off\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"NoFunction\",\n          \"comment\": \"reserved\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"pan/tilt speed mode\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"pan/tilt time mode\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"blackout while pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"disabled blackout while pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"blackout while colour wheel moving\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"disabled blackout while colour wheel moving\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"blackout while gobo 1/gobo 2 moving\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"disabled blackout while gobo 1/gobo 2 moving\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp on, reset\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"pan/tilt reset\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"colour system reset\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"gobo system reset\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"dimmer/strobe reset\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"focus/zoom/frost reset\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"iris/effect/reset\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"total reset\"\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"NoFunction\",\n          \"comment\": \"reserved\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lamp off\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"reserved\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Disabled\"\n        },\n        {\n          \"dmxRange\": [10, 31],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Circle\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Horizontal Eight\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Vertical Eight\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rectangle\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Triangle\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Star\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Cross\",\n          \"parameterStart\": \"small\",\n          \"parameterEnd\": \"big\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"No macro\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [19, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [38, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [56, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [73, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [74, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [91, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [92, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [110, 110],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [111, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [190, 215],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [218, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"random color by audio control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"auto random color\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"5600K\",\n        \"colorTemperatureEnd\": \"3200K\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 1\",\n          \"helpWanted\": \"Which colors are Macro 1 until Macro 63?\"\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 28\"\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 29\"\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 30\"\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 31\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 32\"\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 33\"\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 34\"\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 35\"\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 36\"\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 37\"\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 38\"\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 39\"\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 40\"\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 41\"\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 42\"\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 43\"\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 44\"\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 45\"\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 46\"\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 47\"\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 48\"\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 49\"\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 50\"\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 51\"\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 52\"\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 53\"\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 54\"\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 55\"\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 56\"\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 57\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 58\"\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 59\"\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 60\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 61\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 62\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Macro 63\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Effect Speed assigning\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer + CMY filters + correction filter\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CMY filters + correction filter\"\n        },\n        {\n          \"dmxRange\": [96, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [14, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [18, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [22, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [58, 69],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 81],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [82, 93],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [94, 105],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [106, 117],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [118, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 indexing\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 141],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [142, 153],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 165],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 177],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [178, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 201],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [202, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo by audio control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"switchChannels\": {\n            \"Gobo 1 indexing/rotation\": \"Gobo 1 rotation\",\n            \"Gobo 1 indexing/rotation fine\": \"Gobo 1 rotation fine\"\n          }\n        }\n      ]\n    },\n    \"Gobo 1 indexing\": {\n      \"fineChannelAliases\": [\"Gobo 1 indexing fine\"],\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Gobo Wheel 1\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo 1 rotation\": {\n      \"fineChannelAliases\": [\"Gobo 1 rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 1\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [14, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [18, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [22, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 33],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [38, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [46, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [54, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [58, 69],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 81],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [82, 93],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [94, 105],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [106, 117],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [118, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexed\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 indexing\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 141],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [142, 153],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 165],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [166, 177],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [178, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 201],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [202, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"random gobo selection by audio control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"auto random gobo selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"switchChannels\": {\n            \"Gobo 2 indexing/rotation\": \"Gobo 2 rotation\",\n            \"Gobo 2 indexing/rotation fine\": \"Gobo 2 rotation fine\"\n          }\n        }\n      ]\n    },\n    \"Gobo 2 indexing\": {\n      \"fineChannelAliases\": [\"Gobo 2 indexing fine\"],\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Gobo Wheel 2\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo 2 rotation\": {\n      \"fineChannelAliases\": [\"Gobo 2 rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Effect wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\",\n          \"comment\": \"open\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect indexing\",\n            \"Effect indexing/rotation fine\": \"Effect indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"index 3-facet prism\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect indexing\",\n            \"Effect indexing/rotation fine\": \"Effect indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"index 5-facet prism\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect indexing\",\n            \"Effect indexing/rotation fine\": \"Effect indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"index estriado\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect indexing\",\n            \"Effect indexing/rotation fine\": \"Effect indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"index diamante\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect indexing\",\n            \"Effect indexing/rotation fine\": \"Effect indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"rotation 3-facet prism\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"rotation 5-facet prism\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"rotation estriado\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"rotation diamante\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 1\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 2\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 3\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 4\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 5\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 6\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 7\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 8\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 9\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 10\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 11\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 12\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 13\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 14\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 15\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"macro 16\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"random effect by audio control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"auto random\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"switchChannels\": {\n            \"Effect indexing/rotation\": \"Effect rotation\",\n            \"Effect indexing/rotation fine\": \"Effect rotation fine\"\n          }\n        }\n      ]\n    },\n    \"Effect indexing\": {\n      \"fineChannelAliases\": [\"Effect indexing fine\"],\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Effect rotation\": {\n      \"fineChannelAliases\": [\"Effect rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [1, 179],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"off\",\n          \"frostIntensityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        },\n        {\n          \"dmxRange\": [190, 211],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [212, 233],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramping\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"helpWanted\": \"Is this ramp up and down?\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [1, 179],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"open\",\n          \"openPercentEnd\": \"closed\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [192, 203],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [204, 215],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp up\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [218, 219],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp up\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [220, 221],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp down\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp down\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Shutter, Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Lamp power reduced to 800W\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"15Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Lamp power reduced to 800W\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Electronic strobing (Zap)\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"24-channel 1\",\n      \"shortName\": \"24ch1\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special functions\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Temperature\",\n        \"Effect Speed\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 indexing/rotation\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 indexing/rotation\",\n        \"Effect wheel\",\n        \"Effect indexing/rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Shutter, Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"32-channel\",\n      \"shortName\": \"32ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special functions\",\n        \"Pan/Tilt Macro\",\n        \"Pan/Tilt Macro Speed\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Temperature\",\n        \"Color Macros\",\n        \"Effect Speed\",\n        \"Effect Speed assigning\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 indexing/rotation\",\n        \"Gobo 1 indexing/rotation fine\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 indexing/rotation\",\n        \"Gobo 2 indexing/rotation fine\",\n        \"Effect wheel\",\n        \"Effect indexing/rotation\",\n        \"Effect indexing/rotation fine\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Shutter, Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"24-channel 2\",\n      \"shortName\": \"24ch2\",\n      \"channels\": [\n        \"Shutter, Strobe\",\n        \"Dimmer\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Temperature\",\n        \"Color Wheel\",\n        \"Gobo Wheel 1\",\n        \"Gobo 1 indexing/rotation\",\n        \"Gobo 1 indexing/rotation fine\",\n        \"Gobo Wheel 2\",\n        \"Gobo 2 indexing/rotation\",\n        \"Gobo 2 indexing/rotation fine\",\n        \"Effect wheel\",\n        \"Effect indexing/rotation\",\n        \"Iris\",\n        \"Focus\",\n        \"Zoom\",\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/dj-scan-250-xt.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DJ Scan 250 XT\",\n  \"shortName\": \"Scan250XT\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-01-20\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/api/support-files/download/downloads/user_manuals/User%20manual%20DJ%20Scan%20250%20XT.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/scan-250-xt\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=XLChI_YjDFM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [308, 163, 483],\n    \"weight\": 9.5,\n    \"power\": 500,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"MSD 250\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [19.0, 19.0]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Turquoise\",\n          \"colors\": [\"#40e0d0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light green\",\n          \"colors\": [\"#90ee90\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ca1f7b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#add8e6\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#bf00fe\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Split Red / Blue\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Split Yellow / Green\",\n          \"colors\": [\"#ffff00\", \"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Split Pink / Blue\",\n          \"colors\": [\"#ffc0cb\", \"#0000ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Color Wheel\": {\n      \"precedence\": \"HTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [24, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [48, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [80, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [104, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [128, 151],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [152, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [176, 207],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [208, 231],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        }\n      ]\n    },\n    \"Gobo rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"highlightValue\": 110,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [1, 63],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"off\",\n          \"brightnessEnd\": \"bright\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"8Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [128, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo rotation\",\n        \"Shutter / Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/robin-300e-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Robin 300E Wash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"stevebrush\"],\n    \"createDate\": \"2019-03-02\",\n    \"lastModifyDate\": \"2019-03-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/api/support-files/download/downloads/user_manuals/User_manual_Robin_300E_Wash.pdf\",\n      \"https://www.robe.cz/api/support-files/download/downloads/gobo_config/CW_7_1_Robin_300E_Wash.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/robin-300e-wash\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Eb7pz-xpo2g\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 34,\n    \"softwareVersion\": \"2.9\"\n  },\n  \"physical\": {\n    \"dimensions\": [432.6, 516.2, 409.2],\n    \"weight\": 20,\n    \"power\": 440,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"Philips MSR Gold 300/2 MiniFastFit\",\n      \"colorTemperature\": 9300,\n      \"lumens\": 23000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 40]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"direction\": \"CCW\",\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep red (99011881)\",\n          \"colors\": [\"#e23022\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep blue (99011882)\",\n          \"colors\": [\"#0251ab\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange (99011884)\",\n          \"colors\": [\"#ffa54d\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green (99011883)\",\n          \"colors\": [\"#00ab4f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light red (99011887)\",\n          \"colors\": [\"#ff4f40\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber (99011886)\",\n          \"colors\": [\"#ffc64f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV (99011885)\",\n          \"colors\": [\"#1d2971\"]\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"260deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Power/Special Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt speed mode (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt time mode (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while pan/tilt moving (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while pan/tilt moving (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while color wheel moving (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while color wheel moving (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [110, 129],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on + total reset except pan/tilt\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color system reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer/shutter/hot-spot reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [17, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [33, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [49, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [65, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [80, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [81, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [97, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [130, 137],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [138, 145],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [146, 153],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [154, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [164, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [172, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [190, 215],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CCW\",\n          \"speedEnd\": \"slow CCW\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [218, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color sound-controlled\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO Filter\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"8800K\",\n        \"colorTemperatureEnd\": \"3200K\"\n      }\n    },\n    \"CMY Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 28\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 29\"\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 30\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color macro sound-controlled\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color macro\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"CMY & CTO Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\",\n        \"comment\": \"Flags movement\"\n      }\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"4deg\",\n        \"angleEnd\": \"40deg\"\n      }\n    },\n    \"Hot-Spot\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\",\n        \"parameterStart\": \"high\",\n        \"parameterEnd\": \"low\",\n        \"comment\": \"Beam distribution\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Lamp power = 180W\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"15Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Lamp power = 180W\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"33Hz\",\n          \"comment\": \"electronic zapping\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1st\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special Functions\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO Filter\",\n        \"CMY Color Macros\",\n        \"CMY & CTO Speed\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Hot-Spot\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"2nd\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special Functions\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO Filter\",\n        \"CMY Color Macros\",\n        \"CMY & CTO Speed\",\n        \"Zoom\",\n        \"Hot-Spot\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"3rd\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special Functions\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO Filter\",\n        \"CMY Color Macros\",\n        \"CMY & CTO Speed\",\n        \"Zoom\",\n        \"Hot-Spot\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/robin-600e-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Robin 600E Spot\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"NiKoyes\", \"Flo Edelmann\", \"Ryan Goodwin\"],\n    \"createDate\": \"2018-02-02\",\n    \"lastModifyDate\": \"2023-07-12\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-02-02\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.3.2)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/api/support-files/download/downloads/user_manuals/User_manual_Robin_600E_Spot.pdf\",\n      \"https://www.robe.cz/res/downloads/dmx_charts/Robin_600E_Spot_DMX_charts.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/robin-600e-spot\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2osNE5rpbi8\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 57,\n    \"softwareVersion\": \"1.1\"\n  },\n  \"physical\": {\n    \"dimensions\": [432.6, 515.8, 469.1],\n    \"weight\": 21.7,\n    \"power\": 750,\n    \"powerConnectors\": {\n      \"Hardwired\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"MSR 575W/2\",\n      \"colorTemperature\": 7500,\n      \"lumens\": 37000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 45]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep Red\",\n          \"colors\": [\"#aa0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Red\",\n          \"colors\": [\"#ff4000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV Filter\",\n          \"colors\": [\"#8800ff\"]\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"280deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Tracking Mode\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Vector Mode\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt speed mode\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt Time Mode\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout Pan/Tilt moving\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable Blackout Pan/Tilt moving\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout colour wheel moving\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable Blackout colour wheel moving\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout gobo wheel moving\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable Blackout gobo wheel moving\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp ON / reset (except Pan/Tilt)\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt Reset\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Reset\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo Reset\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer/Shutter/HotSpot Reset\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom/Focus/Frost/Prism Reset\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Iris Reset\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total Reset\"\n        },\n        {\n          \"dmxRange\": [210, 229],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp Off\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable \\\"Silent\\\" Mode of fans\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent mode of Fans min to max\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [17, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [33, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [48, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [49, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [65, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [80, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [81, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [97, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [112, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [113, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [130, 137],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [138, 145],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [146, 153],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [154, 163],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [164, 171],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [172, 181],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [190, 215],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [218, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Color by audio control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto random color selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTO Filter\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"6900K\",\n        \"colorTemperatureEnd\": \"3200K\"\n      }\n    },\n    \"CMY Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 16\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 17\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 18\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 19\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 20\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 21\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 22\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 23\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 24\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 25\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 26\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 27\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 28\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 29\"\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 30\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Macro selection by audio control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto random selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\",\n        \"comment\": \"CMY/CTO or Gobo Selection speed\"\n      }\n    },\n    \"Static Gobo Wheel\": {\n      \"fineChannelAliases\": [\"Static Gobo Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 12],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [13, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [14, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [19, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [20, 25],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [26, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [27, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [33, 38],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [39, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [45, 45],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [52, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [58, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [59, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [202, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [224, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Gobo selection by audio control\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Random Gobo selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [202, 221],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Gobo selection by audio control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Random Gobo selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        }\n      ]\n    },\n    \"Rotating Gobo Indexing\": {\n      \"fineChannelAliases\": [\"Rotating Gobo Indexing fine\"],\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Rotating Gobo Rotation\": {\n      \"fineChannelAliases\": [\"Rotating Gobo Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet Rotating\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 1\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 2\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 3\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 4\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 5\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 6\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 7\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 8\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 9\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 10\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 11\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 12\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 13\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 14\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Prism/Gobo Macro 16\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 179],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"0%\",\n          \"frostIntensityEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"100%\"\n        },\n        {\n          \"dmxRange\": [190, 211],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [212, 233],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramping\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"helpWanted\": \"Is this ramp up and down?\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"fineChannelAliases\": [\"Iris fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [1, 179],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"open\",\n          \"openPercentEnd\": \"closed\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [192, 219],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp up\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [220, 247],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Ramp down\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [248, 249],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp up\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 251],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp up\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [252, 253],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp down\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random ramp down\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Hot Spot\": {\n      \"capability\": {\n        \"type\": \"Maintenance\",\n        \"comment\": \"Beam distribution\",\n        \"parameterStart\": \"high\",\n        \"parameterEnd\": \"low\"\n      }\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Lamp power reduced to 260W\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Lamp power reduced to 260W\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Electronic strobing (Zap)\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"32-channel\",\n      \"shortName\": \"32ch\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Control\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO Filter\",\n        \"CMY Macros\",\n        \"Effect Speed\",\n        \"Static Gobo Wheel\",\n        \"Static Gobo Wheel fine\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Control\",\n        \"Rotating Gobo Control fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Iris fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Hot Spot\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"25-channel\",\n      \"shortName\": \"25ch\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Control\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO Filter\",\n        \"CMY Macros\",\n        \"Effect Speed\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Control\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Hot Spot\",\n        \"Shutter\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"23-channel\",\n      \"shortName\": \"23ch\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Control\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTO Filter\",\n        \"CMY Macros\",\n        \"Effect Speed\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Control\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Hot Spot\",\n        \"Shutter\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/robin-ledbeam-100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Robin LEDBeam 100\",\n  \"shortName\": \"RobinLEDBeam100\",\n  \"categories\": [\"Moving Head\", \"Color Changer\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"ameisso\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-01-21\",\n    \"lastModifyDate\": \"2019-01-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/api/support-files/download/downloads/user_manuals/User_manual_Robin_100_LEDBeam.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/ledbeam-100\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VKBPEIBDmO0\",\n      \"https://www.youtube.com/watch?v=wG1ZXgwWQIg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [233, 314, 149],\n    \"weight\": 4.5,\n    \"power\": 200,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 5960\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 7]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null,  \"1\", null,  \"2\", null],\n        [ \"3\", null,  \"4\", null,  \"5\"],\n        [null,  \"6\", null,  \"7\", null],\n        [ \"8\", null,  \"9\", null, \"10\"],\n        [null, \"11\", null, \"12\", null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Zone 1\": [\"4\", \"6\", \"7\", \"9\"],\n      \"Zone 2\": [\"8\", \"10\", \"11\", \"12\"],\n      \"Zone 3\": [\"1\", \"2\", \"3\", \"5\"],\n      \"All Zones\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"450deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"300deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"durationStart\": \"0.1s\",\n        \"durationEnd\": \"25.5s\"\n      }\n    },\n    \"Special functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW color mixing mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CMY color mixing mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt speed mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt time mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable blackout while pan/tilt moving\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout while pan/tilt moving\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [90, 109],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable color calibration mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable color calibration mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable tilt movement reduction\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable tilt movement reduction\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [150, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"CTC\": {\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"19000K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Virtual Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"2700K\",\n          \"colors\": [\"#ffa757\"]\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Halogen lamp mode\",\n          \"colorTemperature\": \"2700K\",\n          \"colors\": [\"#ffa757\"]\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"3200K\",\n          \"colors\": [\"#ffb87b\"]\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White Halogen lamp mode\",\n          \"colorTemperature\": \"3200K\",\n          \"colors\": [\"#ffb87b\"]\n        },\n        {\n          \"dmxRange\": [7, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"4200K\",\n          \"colors\": [\"#ffd3af\"]\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"5600K\",\n          \"colors\": [\"#ffefe1\"]\n        },\n        {\n          \"dmxRange\": [13, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colorTemperature\": \"8000K\",\n          \"colors\": [\"#dde6ff\"]\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [17, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Cyan\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [57, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Green\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [97, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Yellow\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [136, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Red\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [176, 214],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Magenta\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [215, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [216, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Blue\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 1\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 2\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 3\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 4\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 5\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 6\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Zones 2 and 3 only\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"All Zones\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Virtual Color Wheel\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\",\n          \"comment\": \"Virtual Color Wheel\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"All Zones\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"All Zones\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Random Zone\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"comment\": \"Random Zone\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"comment\": \"All Zones\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"fineChannelAliases\": [\"Red $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Cyan $pixelKey\": {\n      \"fineChannelAliases\": [\"Cyan $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"fineChannelAliases\": [\"Green $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Magenta $pixelKey\": {\n      \"fineChannelAliases\": [\"Magenta $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"fineChannelAliases\": [\"Blue $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Yellow $pixelKey\": {\n      \"fineChannelAliases\": [\"Yellow $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"fineChannelAliases\": [\"White $pixelKey fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGBW Pixel\",\n      \"shortName\": \"1-rgbw\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Red Zone 1\",\n        \"Red Zone 1 fine\",\n        \"Green Zone 1\",\n        \"Green Zone 1 fine\",\n        \"Blue Zone 1\",\n        \"Blue Zone 1 fine\",\n        \"White Zone 1\",\n        \"White Zone 1 fine\",\n        \"Red Zone 2\",\n        \"Red Zone 2 fine\",\n        \"Green Zone 2\",\n        \"Green Zone 2 fine\",\n        \"Blue Zone 2\",\n        \"Blue Zone 2 fine\",\n        \"White Zone 2\",\n        \"White Zone 2 fine\",\n        \"Red Zone 3\",\n        \"Red Zone 3 fine\",\n        \"Green Zone 3\",\n        \"Green Zone 3 fine\",\n        \"Blue Zone 3\",\n        \"Blue Zone 3 fine\",\n        \"White Zone 3\",\n        \"White Zone 3 fine\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"CMY Pixel\",\n      \"shortName\": \"1-cmy\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Cyan Zone 1\",\n        \"Cyan Zone 1 fine\",\n        \"Magenta Zone 1\",\n        \"Magenta Zone 1 fine\",\n        \"Yellow Zone 1\",\n        \"Yellow Zone 1 fine\",\n        null,\n        null,\n        \"Cyan Zone 2\",\n        \"Cyan Zone 2 fine\",\n        \"Magenta Zone 2\",\n        \"Magenta Zone 2 fine\",\n        \"Yellow Zone 2\",\n        \"Yellow Zone 2 fine\",\n        null,\n        null,\n        \"Cyan Zone 3\",\n        \"Cyan Zone 3 fine\",\n        \"Magenta Zone 3\",\n        \"Magenta Zone 3 fine\",\n        \"Yellow Zone 3\",\n        \"Yellow Zone 3 fine\",\n        null,\n        null,\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit RGBW Color\",\n      \"shortName\": \"2-rgbw\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Red All Zones\",\n        \"Red All Zones fine\",\n        \"Green All Zones\",\n        \"Green All Zones fine\",\n        \"Blue All Zones\",\n        \"Blue All Zones fine\",\n        \"White All Zones\",\n        \"White All Zones fine\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"Single 16bit CMY Color\",\n      \"shortName\": \"2-cmy\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Cyan All Zones\",\n        \"Cyan All Zones fine\",\n        \"Magenta All Zones\",\n        \"Magenta All Zones fine\",\n        \"Yellow All Zones\",\n        \"Yellow All Zones fine\",\n        null,\n        null,\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"Single 8bit RGBW Color\",\n      \"shortName\": \"3-rgbw\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Red All Zones\",\n        \"Green All Zones\",\n        \"Blue All Zones\",\n        \"White All Zones\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Single 8bit CMY Color\",\n      \"shortName\": \"3-cmy\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Cyan All Zones\",\n        \"Magenta All Zones\",\n        \"Yellow All Zones\",\n        null,\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Virtual Color Wheel\",\n      \"shortName\": \"4\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Virtual Color Wheel\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Reordered RGBW Pixel\",\n      \"shortName\": \"5-rgbw\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Red Zone 1\",\n        \"Red Zone 1 fine\",\n        \"Green Zone 1\",\n        \"Green Zone 1 fine\",\n        \"Blue Zone 1\",\n        \"Blue Zone 1 fine\",\n        \"White Zone 1\",\n        \"White Zone 1 fine\",\n        \"Red Zone 2\",\n        \"Red Zone 2 fine\",\n        \"Green Zone 2\",\n        \"Green Zone 2 fine\",\n        \"Blue Zone 2\",\n        \"Blue Zone 2 fine\",\n        \"White Zone 2\",\n        \"White Zone 2 fine\",\n        \"Red Zone 3\",\n        \"Red Zone 3 fine\",\n        \"Green Zone 3\",\n        \"Green Zone 3 fine\",\n        \"Blue Zone 3\",\n        \"Blue Zone 3 fine\",\n        \"White Zone 3\",\n        \"White Zone 3 fine\"\n      ]\n    },\n    {\n      \"name\": \"Reordered CMY Pixel\",\n      \"shortName\": \"5-cmy\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Cyan Zone 1\",\n        \"Cyan Zone 1 fine\",\n        \"Magenta Zone 1\",\n        \"Magenta Zone 1 fine\",\n        \"Yellow Zone 1\",\n        \"Yellow Zone 1 fine\",\n        null,\n        null,\n        \"Cyan Zone 2\",\n        \"Cyan Zone 2 fine\",\n        \"Magenta Zone 2\",\n        \"Magenta Zone 2 fine\",\n        \"Yellow Zone 2\",\n        \"Yellow Zone 2 fine\",\n        null,\n        null,\n        \"Cyan Zone 3\",\n        \"Cyan Zone 3 fine\",\n        \"Magenta Zone 3\",\n        \"Magenta Zone 3 fine\",\n        \"Yellow Zone 3\",\n        \"Yellow Zone 3 fine\",\n        null,\n        null\n      ]\n    },\n    {\n      \"name\": \"LEDWash 300 RGBW\",\n      \"shortName\": \"6-rgbw\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Red Zone 1\",\n        \"Red Zone 1 fine\",\n        \"Green Zone 1\",\n        \"Green Zone 1 fine\",\n        \"Blue Zone 1\",\n        \"Blue Zone 1 fine\",\n        \"White Zone 1\",\n        \"White Zone 1 fine\",\n        \"Red Zone 2\",\n        \"Red Zone 2 fine\",\n        \"Green Zone 2\",\n        \"Green Zone 2 fine\",\n        \"Blue Zone 2\",\n        \"Blue Zone 2 fine\",\n        \"White Zone 2\",\n        \"White Zone 2 fine\",\n        \"Red Zone 3\",\n        \"Red Zone 3 fine\",\n        \"Green Zone 3\",\n        \"Green Zone 3 fine\",\n        \"Blue Zone 3\",\n        \"Blue Zone 3 fine\",\n        \"White Zone 3\",\n        \"White Zone 3 fine\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        null,\n        null,\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"LEDWash 300 CMY\",\n      \"shortName\": \"6-cmy\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special functions\",\n        \"Cyan Zone 1\",\n        \"Cyan Zone 1 fine\",\n        \"Magenta Zone 1\",\n        \"Magenta Zone 1 fine\",\n        \"Yellow Zone 1\",\n        \"Yellow Zone 1 fine\",\n        null,\n        null,\n        \"Cyan Zone 2\",\n        \"Cyan Zone 2 fine\",\n        \"Magenta Zone 2\",\n        \"Magenta Zone 2 fine\",\n        \"Yellow Zone 2\",\n        \"Yellow Zone 2 fine\",\n        null,\n        null,\n        \"Cyan Zone 3\",\n        \"Cyan Zone 3 fine\",\n        \"Magenta Zone 3\",\n        \"Magenta Zone 3 fine\",\n        \"Yellow Zone 3\",\n        \"Yellow Zone 3 fine\",\n        null,\n        null,\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        null,\n        null,\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/robin-ledbeam-150.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Robin LEDBeam 150\",\n  \"shortName\": \"RobinLEDBeam150\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-01-05\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"comment\": \"Whether to use RGB or CMY depends on the chosen mode in \\\"Special functions\\\"\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/res/downloads/user_manuals/User_manual_Robin_LEDBeam_150_FW_Robin_LEDBeam_150_FWQ.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/ledbeam-150\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ud5DeYkEJsk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [244, 329, 190.3],\n    \"weight\": 5.7,\n    \"power\": 220,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"7x RGBW LEDs\",\n      \"lumens\": 1380\n    },\n    \"lens\": {\n      \"degreesMinMax\": [3.8, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"450deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"228deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"comment\": \"or Time 0.1…25.5s\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Special Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display on\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display off\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW color mixing mode\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CMY color mixing mode\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt speed mode\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt time mode\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"lackout while pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve - square law\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve - linear\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fans mode: Auto\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fans mode: High\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"White point 8000K ON\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"White point 8000K OFF\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fans mode: Quiet\"\n        },\n        {\n          \"dmxRange\": [95, 139],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt reset\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom reset\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (750W) On\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (1000W) On\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (1200W) On\"\n        },\n        {\n          \"dmxRange\": [176, 177],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (2000W) On\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (2500W) On\"\n        },\n        {\n          \"dmxRange\": [180, 181],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation Off\"\n        },\n        {\n          \"dmxRange\": [182, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total fixture reset\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Virtual Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 2],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7600\"],\n          \"comment\": \"Filter 4 (Medium Bastard Amber)\"\n        },\n        {\n          \"dmxRange\": [3, 4],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff2f00\"],\n          \"comment\": \"Filter 25 (Sunset Red)\"\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0d00\"],\n          \"comment\": \"Filter 19 (Fire)\"\n        },\n        {\n          \"dmxRange\": [7, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Filter 26 (Bright Red)\"\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#750061\"],\n          \"comment\": \"Filter 58 (Lavender)\"\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#017cc0\"],\n          \"comment\": \"Filter 68 (Sky Blue)\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff4a08\"],\n          \"comment\": \"Filter 36 (Medium Pink)\"\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#45f500\"],\n          \"comment\": \"Filter 89 (Moss Green)\"\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bbe200\"],\n          \"comment\": \"Filter 88 (Lime Green)\"\n        },\n        {\n          \"dmxRange\": [19, 20],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#027f07\"],\n          \"comment\": \"Filter 90 (Dark Yellow Green)\"\n        },\n        {\n          \"dmxRange\": [21, 22],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff001b\"],\n          \"comment\": \"Filter 49 (Medium Purple)\"\n        },\n        {\n          \"dmxRange\": [23, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dec0ff\"],\n          \"comment\": \"Filter 52 (Light Lavender)\"\n        },\n        {\n          \"dmxRange\": [25, 26],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dfa400\"],\n          \"comment\": \"Filter 102 (Light Amber)\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bf9000\"],\n          \"comment\": \"Filter 103 (Straw)\"\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#87f0eb\"],\n          \"comment\": \"Filter 140 (Summer Blue)\"\n        },\n        {\n          \"dmxRange\": [31, 32],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#1dff00\"],\n          \"comment\": \"Filter 124 (Dark Green)\"\n        },\n        {\n          \"dmxRange\": [33, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f20101\"],\n          \"comment\": \"Filter 106 (Primary Red)\"\n        },\n        {\n          \"dmxRange\": [35, 36],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff430b\"],\n          \"comment\": \"Filter 111 (Dark Pink)\"\n        },\n        {\n          \"dmxRange\": [37, 38],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ecc8\"],\n          \"comment\": \"Filter 115 (Peacock Blue)\"\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bd009a\"],\n          \"comment\": \"Filter 126 (Mauve)\"\n        },\n        {\n          \"dmxRange\": [41, 42],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b3faf4\"],\n          \"comment\": \"Filter 117 (Steel Blue)\"\n        },\n        {\n          \"dmxRange\": [43, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#02e0eb\"],\n          \"comment\": \"Filter 118 (Light Blue)\"\n        },\n        {\n          \"dmxRange\": [45, 46],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#62ff00\"],\n          \"comment\": \"Filter 122 (Fern Green)\"\n        },\n        {\n          \"dmxRange\": [47, 48],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff1002\"],\n          \"comment\": \"Filter 182 (Light Red)\"\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a5ff00\"],\n          \"comment\": \"Filter 121 (Filter Green)\"\n        },\n        {\n          \"dmxRange\": [51, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff000d\"],\n          \"comment\": \"Filter 128 (Bright Pink)\"\n        },\n        {\n          \"dmxRange\": [53, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#64fbd2\"],\n          \"comment\": \"Filter 131 (Marine Blue)\"\n        },\n        {\n          \"dmxRange\": [55, 56],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00a0dc\"],\n          \"comment\": \"Filter 132 (Medium Blue)\"\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a65300\"],\n          \"comment\": \"Filter 134 (Golden Amber)\"\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fba874\"],\n          \"comment\": \"Filter 135 (Deep Golden Amber)\"\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f1bfe5\"],\n          \"comment\": \"Filter 136 (Pale Lavender)\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#b695fd\"],\n          \"comment\": \"Filter 137 (Special Lavender)\"\n        },\n        {\n          \"dmxRange\": [65, 66],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dcffa0\"],\n          \"comment\": \"Filter 138 (Pale Green)\"\n        },\n        {\n          \"dmxRange\": [67, 68],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a100c0\"],\n          \"comment\": \"Filter 798 (Chrysalis Pink)\"\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#01d4e9\"],\n          \"comment\": \"Filter 141 (Bright Blue)\"\n        },\n        {\n          \"dmxRange\": [71, 72],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#be6b00\"],\n          \"comment\": \"Filter 147 (Apricot)\"\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff1471\"],\n          \"comment\": \"Filter 148 (Bright Rose)\"\n        },\n        {\n          \"dmxRange\": [75, 76],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffcaa8\"],\n          \"comment\": \"Filter 152 (Pale Gold)\"\n        },\n        {\n          \"dmxRange\": [77, 78],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb2ba\"],\n          \"comment\": \"Filter 154 (Pale Rose)\"\n        },\n        {\n          \"dmxRange\": [79, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f17692\"],\n          \"comment\": \"Filter 157 (Pink)\"\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#63bed1\"],\n          \"comment\": \"Filter 143 (Pale Navy Blue)\"\n        },\n        {\n          \"dmxRange\": [83, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d39906\"],\n          \"comment\": \"Filter 162 (Bastard Amber)\"\n        },\n        {\n          \"dmxRange\": [85, 86],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff1b00\"],\n          \"comment\": \"Filter 164 (Flame Red)\"\n        },\n        {\n          \"dmxRange\": [87, 88],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#1cadff\"],\n          \"comment\": \"Filter 165 (Daylight Blue)\"\n        },\n        {\n          \"dmxRange\": [89, 90],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fcdcf1\"],\n          \"comment\": \"Filter 169 (Lilac Tint)\"\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e6aadd\"],\n          \"comment\": \"Filter 170 (Deep Lavender)\"\n        },\n        {\n          \"dmxRange\": [93, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00dcdc\"],\n          \"comment\": \"Filter 172 (Lagoon Blue)\"\n        },\n        {\n          \"dmxRange\": [95, 96],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bf8af2\"],\n          \"comment\": \"Filter 194 (Surprise Pink)\"\n        },\n        {\n          \"dmxRange\": [97, 98],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#882bb5\"],\n          \"comment\": \"Filter 180 (Dark Lavender)\"\n        },\n        {\n          \"dmxRange\": [99, 100],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#1800ff\"],\n          \"comment\": \"Filter 181 (Congo Blue)\"\n        },\n        {\n          \"dmxRange\": [101, 102],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#83a9e7\"],\n          \"comment\": \"Filter 197 (Alice Blue)\"\n        },\n        {\n          \"dmxRange\": [103, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c3e1fb\"],\n          \"comment\": \"Filter 201\",\n          \"colorTemperature\": \"100%\"\n        },\n        {\n          \"dmxRange\": [105, 106],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d7f1fe\"],\n          \"comment\": \"Filter 202\",\n          \"colorTemperature\": \"50%\"\n        },\n        {\n          \"dmxRange\": [107, 108],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#eafcfe\"],\n          \"comment\": \"Filter 203\",\n          \"colorTemperature\": \"25%\"\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fac488\"],\n          \"comment\": \"Filter 204\",\n          \"colorTemperature\": \"-100%\"\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#9adcae\"],\n          \"comment\": \"Filter 219 (Fluorescent Green)\"\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fcead6\"],\n          \"comment\": \"Filter 206\",\n          \"colorTemperature\": \"-25%\"\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e587b9\"],\n          \"comment\": \"Filter 247 (Filter Minus Green)\"\n        },\n        {\n          \"dmxRange\": [117, 118],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffe2e6\"],\n          \"comment\": \"Filter 248 (Half Minus Green)\"\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cde6fa\"],\n          \"comment\": \"Filter 281\",\n          \"colorTemperature\": \"75%\"\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fec68b\"],\n          \"comment\": \"Filter 285\",\n          \"colorTemperature\": \"-75%\"\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#5ac7e4\"],\n          \"comment\": \"Filter 352 (Glacier Blue)\"\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#61e8e2\"],\n          \"comment\": \"Filter 353 (Lighter Blue)\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#f94f02\"],\n          \"comment\": \"Filter 507 (Madge)\"\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff7701\"],\n          \"comment\": \"Filter 778 (Millennium Gold)\"\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff3ca2\"],\n          \"comment\": \"Filter 793 (Vanity Fair)\"\n        },\n        {\n          \"dmxRange\": [133, 235],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Raw DMX\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"fineChannelAliases\": [\"Magenta fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"fineChannelAliases\": [\"Yellow fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CTC\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"8000K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Color Mix Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Virtual Color Wheel has priority\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Highest values have priority\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lowest values have priority\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Multiply wheel and color mix\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Add wheel and color mix\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Subtract color mix from wheel\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Substract wheel from color mix\"\n        },\n        {\n          \"dmxRange\": [70, 128],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Virtual Color Wheel has priority\"\n        },\n        {\n          \"dmxRange\": [130, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Crossfade between wheel and color mix\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color mix has priority\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"60deg\",\n        \"angleEnd\": \"3.8deg\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1 – Standard 16bit RGBW\",\n      \"shortName\": \"1-16bitRGBW\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Virtual Color Wheel\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTC\",\n        \"Color Mix Control\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"2 – Reduced 8bit RGBW\",\n      \"shortName\": \"2-8bitRGBW\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Virtual Color Wheel\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CTC\",\n        \"Color Mix Control\",\n        \"Zoom\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"1 – Standard 16bit CMY\",\n      \"shortName\": \"1-16bitCMY\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Virtual Color Wheel\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\",\n        null,\n        null,\n        \"CTC\",\n        \"Color Mix Control\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"2 – Reduced 8bit CMY\",\n      \"shortName\": \"2-8bitCMY\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Virtual Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        null,\n        \"CTC\",\n        \"Color Mix Control\",\n        \"Zoom\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/robin-ledwash-600.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Robin LEDWash 600\",\n  \"shortName\": \"RobinLEDWash600\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-01-01\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/api/support-files/download/downloads/user_manuals/User_manual_Robin_600_LEDWash.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/ledwash-600\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Q-vweXSfuUg\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 118,\n    \"softwareVersion\": \"47\"\n  },\n  \"physical\": {\n    \"dimensions\": [343, 444, 203],\n    \"weight\": 10.6,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"37x Cree RGBW LEDs\",\n      \"lumens\": 4820\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 63]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null,  null,  null,  \"O1\",  null,  \"O2\",  null,  \"O3\",  null,  \"O4\",  null,  null,  null],\n        [null,  null,  null,  null,  null,  null,  null,  null,  null,  null,  null,  null,  null],\n        [null,  \"O5\",  null,  null,  null,  \"M1\",  null,  \"M2\",  null,  null,  null,  \"O5\",  null],\n        [null,  null,  null,  \"M12\", null,  null,  null,  null,  null,  \"M3\",  null,  null,  null],\n        [\"O17\", null,  null,  null,  null,  \"I1\",  null,  \"I2\",  null,  null,  null,  null,  \"O6\"],\n        [null,  null,  \"M11\", null,  null,  null,  null,  null,  null,  null,  \"M4\",  null,  null],\n        [\"O16\", null,  null,  null,  \"I6\",  null,  \"I7\",  null,  \"I3\",  null,  null,  null,  \"O7\"],\n        [null,  null,  \"M10\", null,  null,  null,  null,  null,  null,  null,  \"M5\",  null,  null],\n        [\"O15\", null,  null,  null,  null,  \"I5\",  null,  \"I4\",  null,  null,  null,  null,  \"O8\"],\n        [null,  null,  null,  \"M9\",  null,  null,  null,  null,  null,  \"M6\",  null,  null,  null],\n        [null,  \"O14\", null,  null,  null,  \"M8\",  null,  \"M7\",  null,  null,  null,  \"O9\",  null],\n        [null,  null,  null,  null,  null,  null,  null,  null,  null,  null,  null,  null,  null],\n        [null,  null,  null,  \"O13\", null,  \"O12\", null,  \"O11\", null,  \"O10\", null,  null,  null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Inner\": { \"name\": [\"^I[1-7]$\"] },\n      \"Middle\": { \"name\": [\"^M\\\\d+$\"] },\n      \"Outer\": { \"name\": [\"^O\\\\d+$\"] },\n      \"All Zones\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"450deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"300deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"comment\": \"or Time 0.1…25.5s\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX input: Wired DMX\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX input: Wireless DMX\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [20, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt speed mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt time mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while pan/tilt moving\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while pan/tilt moving\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre mode On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theatre mode Off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [110, 139],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [150, 179],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [210, 239],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable \\\"Silent mode\\\"\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Silent mode: Fan noise\",\n          \"parameterStart\": \"low\",\n          \"parameterEnd\": \"high\",\n          \"hold\": \"3s\"\n        }\n      ]\n    },\n    \"CTC\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"15500K\",\n          \"colorTemperatureEnd\": \"2700K\",\n          \"comment\": \"or 20000…2700K with color calibration off\"\n        }\n      ]\n    },\n    \"Virtual Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 2],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa757\"],\n          \"colorTemperature\": \"2700K\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffa757\"],\n          \"colorTemperature\": \"2700K\",\n          \"comment\": \"Halogen White\"\n        },\n        {\n          \"dmxRange\": [4, 5],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"Halogen White\"\n        },\n        {\n          \"dmxRange\": [7, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd3af\"],\n          \"colorTemperature\": \"4200K\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [10, 12],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"colorTemperature\": \"5600K\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [13, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dde6ff\"],\n          \"colorTemperature\": \"8000K\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [16, 16],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#007cc3\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [17, 55],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#007cc3\"],\n          \"colorsEnd\": [\"#61afca\"],\n          \"comment\": \"Blue - Cyan\"\n        },\n        {\n          \"dmxRange\": [56, 56],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#61afca\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [57, 95],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#61afca\"],\n          \"colorsEnd\": [\"#87c326\"],\n          \"comment\": \"Cyan - Green\"\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#87c326\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [97, 134],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#87c326\"],\n          \"colorsEnd\": [\"#ebd82a\"],\n          \"comment\": \"Green - Yellow\"\n        },\n        {\n          \"dmxRange\": [135, 135],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ebd82a\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [136, 174],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ebd82a\"],\n          \"colorsEnd\": [\"#dc2c4e\"],\n          \"comment\": \"Yellow - Red\"\n        },\n        {\n          \"dmxRange\": [175, 175],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dc2c4e\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [176, 214],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#dc2c4e\"],\n          \"colorsEnd\": [\"#bb4e8b\"],\n          \"comment\": \"Red - Magenta\"\n        },\n        {\n          \"dmxRange\": [215, 215],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bb4e8b\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [216, 246],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#bb4e8b\"],\n          \"colorsEnd\": [\"#0093dc\"],\n          \"comment\": \"Magenta - Blue\"\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0093dc\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 1\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 2\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 3\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 4\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 5\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Zone effect 6\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"15deg\",\n        \"angleEnd\": \"63deg\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Outer zone\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"EffectSpeed\",\n          \"comment\": \"Color effect speed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"EffectSpeed\",\n          \"comment\": \"Color effect speed\",\n          \"speedStart\": \"fast reverse\",\n          \"speedEnd\": \"slow reverse\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Random zone\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"Random zone\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"fineChannelAliases\": [\"Red $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"fineChannelAliases\": [\"Green $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"fineChannelAliases\": [\"Blue $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"fineChannelAliases\": [\"White $pixelKey fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1st\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Inner\", \"Middle\", \"Outer\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Red $pixelKey fine\",\n            \"Green $pixelKey\",\n            \"Green $pixelKey fine\",\n            \"Blue $pixelKey\",\n            \"Blue $pixelKey fine\",\n            \"White $pixelKey\",\n            \"White $pixelKey fine\"\n          ]\n        },\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"2nd\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Red All Zones\",\n        \"Red All Zones fine\",\n        \"Green All Zones\",\n        \"Green All Zones fine\",\n        \"Blue All Zones\",\n        \"Blue All Zones fine\",\n        \"White All Zones\",\n        \"White All Zones fine\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"3rd\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Red All Zones\",\n        \"Green All Zones\",\n        \"Blue All Zones\",\n        \"White All Zones\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Zoom\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"4th\",\n      \"rdmPersonalityIndex\": 4,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Virtual Color Wheel\",\n        \"Zoom\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"5th\",\n      \"rdmPersonalityIndex\": 5,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Inner\", \"Middle\", \"Outer\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Red $pixelKey fine\",\n            \"Green $pixelKey\",\n            \"Green $pixelKey fine\",\n            \"Blue $pixelKey\",\n            \"Blue $pixelKey fine\",\n            \"White $pixelKey\",\n            \"White $pixelKey fine\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"6th\",\n      \"rdmPersonalityIndex\": 6,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Special Functions\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Inner\", \"Middle\", \"Outer\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"CTC\",\n        \"Virtual Color Wheel\",\n        \"Zoom\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/robin-parfect-150.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Robin ParFect 150\",\n  \"shortName\": \"RobinParfect150\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Benni\"],\n    \"createDate\": \"2018-09-19\",\n    \"lastModifyDate\": \"2019-01-05\",\n    \"importPlugin\": {\n      \"plugin\": \"gdtf\",\n      \"date\": \"2019-03-19\",\n      \"comment\": \"GDTF fixture type ID: cb cd b4 6b 06 dd 4f 3d a7 32 5a 01 86 5c a7 ec\"\n    }\n  },\n  \"comment\": \"ParFect 150 (FW) is a static, zoomable version of the successful LEDBeam 100 and retains all the key features including both CMY & RGBW colour control, 18-bit dimming, Tungsten emulation, selectable & variable colour temperatures and the powerful punchy beam ranging from 3,8° to 60°.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/res/downloads/user_manuals/User_manual_Robin_Parfect_150_150Q_150_FW_150_FWQ.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/parfect-150-rgbw\",\n      \"https://www.robe.cz/parfect-150-fw-rgbw\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 227,\n    \"softwareVersion\": \"1.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [240, 192, 498],\n    \"weight\": 5,\n    \"power\": 220,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"7x 30W RGBW multichip LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [3.8, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display ON\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Display OFF\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGBW colour mixing mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CMY colour mixing mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve - square law\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve - linear\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode: Auto\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode: High\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"White point 8000K ON\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"White point 8000K OFF\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode: Quiet\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [95, 149],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [170, 171],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (750W) On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (1000W) On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (1200W) On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [176, 177],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (2000W) On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [178, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (2500W) On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [180, 181],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation Off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [182, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Virtual Color wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 4 (Medium Bastard Amber)\",\n          \"colors\": [\"#ff9f4c\"]\n        },\n        {\n          \"dmxRange\": [3, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 25 (Sunset Red)\",\n          \"colors\": [\"#ff3103\"]\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 19 (Fire)\",\n          \"colors\": [\"#ff0d00\"]\n        },\n        {\n          \"dmxRange\": [7, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 26 (Bright Red)\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 58 (Lavender)\",\n          \"colors\": [\"#ff91ec\"]\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 68 (Sky Blue)\",\n          \"colors\": [\"#25e16f\"],\n          \"helpWanted\": \"The \\\"blue\\\" colors from the manual don't seem to match the color names.\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 36 (Medium Pink)\",\n          \"colors\": [\"#ff5a1d\"]\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 89 (Moss Green)\",\n          \"colors\": [\"#48f803\"]\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 88 (Lime Green)\",\n          \"colors\": [\"#bbe200\"]\n        },\n        {\n          \"dmxRange\": [19, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 90 (Dark Yellow Green)\",\n          \"colors\": [\"#02ff00\"]\n        },\n        {\n          \"dmxRange\": [21, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 49 (Medium Purple)\",\n          \"colors\": [\"#ff001b\"]\n        },\n        {\n          \"dmxRange\": [23, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 52 (Light Lavender)\",\n          \"colors\": [\"#ffa36e\"]\n        },\n        {\n          \"dmxRange\": [25, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 102 (Light Amber)\",\n          \"colors\": [\"#dfa400\"]\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 103 (Straw)\",\n          \"colors\": [\"#dbac1c\"]\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 140 (Summer Blue)\",\n          \"colors\": [\"#98ff9a\"]\n        },\n        {\n          \"dmxRange\": [31, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 124 (Dark Green)\",\n          \"colors\": [\"#27ff0b\"]\n        },\n        {\n          \"dmxRange\": [33, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 106 (Primary Red)\",\n          \"colors\": [\"#f20101\"]\n        },\n        {\n          \"dmxRange\": [35, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 111 (Dark Pink)\",\n          \"colors\": [\"#ff6132\"]\n        },\n        {\n          \"dmxRange\": [37, 38],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 115 (Peacock Blue)\",\n          \"colors\": [\"#25ff3e\"]\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 126 (Mauve)\",\n          \"colors\": [\"#ff0027\"]\n        },\n        {\n          \"dmxRange\": [41, 42],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 117 (Steel Blue)\",\n          \"colors\": [\"#d4ff77\"]\n        },\n        {\n          \"dmxRange\": [43, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 118 (Light Blue)\",\n          \"colors\": [\"#1bff5f\"]\n        },\n        {\n          \"dmxRange\": [45, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 122 (Fern Green)\",\n          \"colors\": [\"#64ff04\"]\n        },\n        {\n          \"dmxRange\": [47, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 182 (Light Red)\",\n          \"colors\": [\"#ff1002\"]\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 121 (Filter Green)\",\n          \"colors\": [\"#a5ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 128 (Bright Pink)\",\n          \"colors\": [\"#ff1c28\"]\n        },\n        {\n          \"dmxRange\": [53, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 131 (Marine Blue)\",\n          \"colors\": [\"#60ff35\"]\n        },\n        {\n          \"dmxRange\": [55, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 132 (Medium Blue)\",\n          \"colors\": [\"#00e678\"]\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 134 (Golden Amber)\",\n          \"colors\": [\"#a65300\"]\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 135 (Deep Golden Amber)\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 136 (Pale Lavender)\",\n          \"colors\": [\"#b48d41\"]\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 137 (Special Lavender)\",\n          \"colors\": [\"#d4a293\"]\n        },\n        {\n          \"dmxRange\": [65, 66],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 138 (Pale Green)\",\n          \"colors\": [\"#f3ff2c\"]\n        },\n        {\n          \"dmxRange\": [67, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 798 (Chrysalis Pink)\",\n          \"colors\": [\"#4b1a7c\"]\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 141 (Bright Blue)\",\n          \"colors\": [\"#05e643\"]\n        },\n        {\n          \"dmxRange\": [71, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 147 (Apricot)\",\n          \"colors\": [\"#cd7a0f\"]\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 148 (Bright Rose)\",\n          \"colors\": [\"#ff2320\"]\n        },\n        {\n          \"dmxRange\": [75, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 152 (Pale Gold)\",\n          \"colors\": [\"#da9e27\"]\n        },\n        {\n          \"dmxRange\": [77, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 154 (Pale Rose)\",\n          \"colors\": [\"#ffa22f\"]\n        },\n        {\n          \"dmxRange\": [79, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 157 (Pink)\",\n          \"colors\": [\"#ff5529\"]\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 143 (Pale Navy Blue)\",\n          \"colors\": [\"#6fffa1\"]\n        },\n        {\n          \"dmxRange\": [83, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 162 (Bastard Amber)\",\n          \"colors\": [\"#f7bd2a\"]\n        },\n        {\n          \"dmxRange\": [85, 86],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 164 (Flame Red)\",\n          \"colors\": [\"#ff1f04\"]\n        },\n        {\n          \"dmxRange\": [87, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 165 (Daylight Blue)\",\n          \"colors\": [\"#54ff8c\"]\n        },\n        {\n          \"dmxRange\": [89, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 169 (Lilac Tint)\",\n          \"colors\": [\"#ffc95f\"]\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 170 (Deep Lavender)\",\n          \"colors\": [\"#ff9649\"]\n        },\n        {\n          \"dmxRange\": [93, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 172 (Lagoon Blue)\",\n          \"colors\": [\"#05ff43\"]\n        },\n        {\n          \"dmxRange\": [95, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 194 (Surprise Pink)\",\n          \"colors\": [\"#ffb2c1\"]\n        },\n        {\n          \"dmxRange\": [97, 98],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 180 (Dark Lavender)\",\n          \"colors\": [\"#d98aff\"]\n        },\n        {\n          \"dmxRange\": [99, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 181 (Congo Blue)\",\n          \"colors\": [\"#2009ff\"]\n        },\n        {\n          \"dmxRange\": [101, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 197 (Alice Blue)\",\n          \"colors\": [\"#73e5be\"]\n        },\n        {\n          \"dmxRange\": [103, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 201 (Full CT Blue)\",\n          \"colors\": [\"#d0ff95\"]\n        },\n        {\n          \"dmxRange\": [105, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 202 (Half CT Blue)\",\n          \"colors\": [\"#fffa67\"]\n        },\n        {\n          \"dmxRange\": [107, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 203 (Quarter CT Blue)\",\n          \"colors\": [\"#ffea69\"]\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 204 (Full CT Orange)\",\n          \"colors\": [\"#e98606\"]\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 219 (Fluorescent Green)\",\n          \"colors\": [\"#95c642\"]\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 206 (Quarter CT Orange)\",\n          \"colors\": [\"#ffd13b\"]\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 247 (Filter Minus Green)\",\n          \"colors\": [\"#ff996c\"]\n        },\n        {\n          \"dmxRange\": [117, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 248 (Half Minus Green)\",\n          \"colors\": [\"#ffae4e\"]\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 281 (Three Quarter CT Blue)\",\n          \"colors\": [\"#eeffa5\"]\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 285 (Three Quarter CT Orange)\",\n          \"colors\": [\"#c4880f\"]\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 352 (Glacier Blue)\",\n          \"colors\": [\"#5afb8b\"]\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 353 (Lighter Blue)\",\n          \"colors\": [\"#61d476\"]\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 507 (Madge)\",\n          \"colors\": [\"#ff1f00\"]\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 778 (Millennium Gold)\",\n          \"colors\": [\"#ff4100\"]\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 793 (Vanity Fair)\",\n          \"colors\": [\"#ff0f1b\"]\n        },\n        {\n          \"dmxRange\": [133, 235],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Raw DMX\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"CTC\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"8000K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Color Mix Mode\": {\n      \"defaultValue\": 45,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Virtual colors (Virtual has priority)\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Maximum mode (highest values have priority)\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Minimum mode (lowest values have priority)\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Multiply mode (multiply Virtual and Colour Mix)\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Addition mode (Virtual + Colour mix)\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Subtraction mode (Virtual - Colour mix)\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverted Subtraction mode (Colour mix - Virtual)\"\n        },\n        {\n          \"dmxRange\": [70, 128],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Virtual colors (virtual has priority)\"\n        },\n        {\n          \"dmxRange\": [130, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Crossfade (crossfade between Virtual and Colour mix)\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Colour channels (Colour mix has priority)\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"3.8deg\",\n        \"angleEnd\": \"60deg\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.3Hz\",\n          \"speedEnd\": \"20Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard 16bit\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Control\",\n        \"Virtual Color wheel\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"CTC\",\n        \"Color Mix Mode\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"Reduced 8bit\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Control\",\n        \"Virtual Color wheel\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"CTC\",\n        \"Color Mix Mode\",\n        \"Zoom\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/robin-t1-profile.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Robin T1 Profile\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Dyami Caliri\"],\n    \"createDate\": \"2022-09-24\",\n    \"lastModifyDate\": \"2022-09-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/en/pdfs/product/654\",\n      \"https://www.robe.cz/res/downloads/dmx_charts/Robin_T1_Profile_DMX_charts.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/t1-profile\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=6rTbwPAY9Sk\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 249,\n    \"softwareVersion\": \"2.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [726, 400, 258],\n    \"weight\": 24.3,\n    \"power\": 440,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 12600\n    },\n    \"lens\": {\n      \"degreesMinMax\": [7, 49]\n    }\n  },\n  \"wheels\": {\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"265deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Power/Special Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX input: Wired DMX\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"DMX input: Wireless DMX\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Graphic display: On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Graphic display: Off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt speed mode (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt time mode (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while pan/tilt moving (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while pan/tilt moving (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while color wheel moving (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while color wheel moving (shutter must be closed)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fans mode: Auto\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fans mode: High\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [80, 119],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Parking position: On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Parking position: Off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on + total reset except pan/tilt\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/tilt reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo wheel/effect wheel reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom/focus/frost/prism reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Iris/framing shutters reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Total fixture reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [210, 211],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction calibration\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [212, 218],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [219, 220],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Maximum speed and shortcut\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [221, 222],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Follow speed and direction\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [223, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Maximum speed and follow direction\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [225, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RoboSpot enabled\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [230, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RoboSpot disabled - except handle faders and pan/tilt\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [235, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RoboSpot fully disabled\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled Quiet mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Quiet mode - fan noise control from min. to max.\"\n        }\n      ]\n    },\n    \"LED Frequency\": {\n      \"defaultValue\": 10,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Maintenance\",\n          \"comment\": \"PWM frequency\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"300 Hz\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"comment\": \"600 Hz\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"1200 Hz\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"comment\": \"2400 Hz\"\n        },\n        {\n          \"dmxRange\": [25, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"LED Frequency Adjustment\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 1],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Selected frequency\"\n        },\n        {\n          \"dmxRange\": [2, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Freq -126 to +126\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Selected frequency\"\n        }\n      ]\n    },\n    \"Color Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"CMY color mixing mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB color mixing mode\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve: Square law\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve: Linear\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Raw DMX\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (750W)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (1000W)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (1200W)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (2000W)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation (2500W)\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tungsten effect simulation OFF\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Save user color\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Chromatic white: On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Chromatic white: Off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Light output stability On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Light output stability Off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Uniformity On\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Uniformity Off\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 2700K/CRI 70\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 3200K/CRI 70\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 4200K/CRI 70\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 5600K/CRI 70\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [165, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 8000K/CRI 70\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [170, 174],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 2700K/CRI 90\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [175, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 3200K/CRI 90\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [180, 184],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 4200K/CRI 90\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [185, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 5600K/CRI 90\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [190, 194],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Green correction - 8000K/CRI 70\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [195, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Save Green correction\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"CRI Selection\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Standard…High\"\n      }\n    },\n    \"Virtual Color wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 4 (Medium Bastard Amber)\",\n          \"colors\": [\"#ff9f4c\"]\n        },\n        {\n          \"dmxRange\": [3, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 10 (Medium Yellow)\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 19 (Fire)\",\n          \"colors\": [\"#ff0d00\"]\n        },\n        {\n          \"dmxRange\": [7, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 26 (Bright Red)\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 58 (Lavender)\",\n          \"colors\": [\"#ff91ec\"]\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 68 (Sky Blue)\",\n          \"colors\": [\"#25e16f\"],\n          \"helpWanted\": \"The \\\"blue\\\" colors from the manual don't seem to match the color names.\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 71 (Tokyo Blue)\",\n          \"colors\": [\"#0000b4\"]\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 79 (Just Blue)\",\n          \"colors\": [\"#3c8cd2\"]\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 88 (Lime Green)\",\n          \"colors\": [\"#bbe200\"]\n        },\n        {\n          \"dmxRange\": [19, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 90 (Dark Yellow Green)\",\n          \"colors\": [\"#02ff00\"]\n        },\n        {\n          \"dmxRange\": [21, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 100 (Spring Yellow)\",\n          \"colors\": [\"#f5ff00\"]\n        },\n        {\n          \"dmxRange\": [23, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 101 (Yellow)\",\n          \"colors\": [\"#fff500\"]\n        },\n        {\n          \"dmxRange\": [25, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 102 (Light Amber)\",\n          \"colors\": [\"#ffdc5f\"]\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 103 (Straw)\",\n          \"colors\": [\"#fceacc\"]\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 104 (Deep Amber)\",\n          \"colors\": [\"#ffdc00\"]\n        },\n        {\n          \"dmxRange\": [31, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 105 (Orange)\",\n          \"colors\": [\"#ffa000\"]\n        },\n        {\n          \"dmxRange\": [33, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 106 (Primary Red)\",\n          \"colors\": [\"#f20101\"]\n        },\n        {\n          \"dmxRange\": [35, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 111 (Dark Pink)\",\n          \"colors\": [\"#ff6132\"]\n        },\n        {\n          \"dmxRange\": [37, 38],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 115 (Peacock Blue)\",\n          \"colors\": [\"#25ff3e\"]\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 116 (Medium Blue-Green)\",\n          \"colors\": [\"#ff0027\"]\n        },\n        {\n          \"dmxRange\": [41, 42],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 117 (Steel Blue)\",\n          \"colors\": [\"#d4ff77\"]\n        },\n        {\n          \"dmxRange\": [43, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 118 (Light Blue)\",\n          \"colors\": [\"#1bff5f\"]\n        },\n        {\n          \"dmxRange\": [45, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 119 (Dark Blue)\",\n          \"colors\": [\"#5c41fd\"]\n        },\n        {\n          \"dmxRange\": [47, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 120 (Deep Blue)\",\n          \"colors\": [\"#5c41fd\"]\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 121 (Filter Green)\",\n          \"colors\": [\"#a5ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 128 (Bright Pink)\",\n          \"colors\": [\"#ff1c28\"]\n        },\n        {\n          \"dmxRange\": [53, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 131 (Marine Blue)\",\n          \"colors\": [\"#60ff35\"]\n        },\n        {\n          \"dmxRange\": [55, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 132 (Medium Blue)\",\n          \"colors\": [\"#00e678\"]\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 134 (Golden Amber)\",\n          \"colors\": [\"#a65300\"]\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 135 (Deep Golden Amber)\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 136 (Pale Lavender)\",\n          \"colors\": [\"#b48d41\"]\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 137 (Special Lavender)\",\n          \"colors\": [\"#d4a293\"]\n        },\n        {\n          \"dmxRange\": [65, 66],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 138 (Pale Green)\",\n          \"colors\": [\"#f3ff2c\"]\n        },\n        {\n          \"dmxRange\": [67, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 139 (Primary Green)\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 141 (Bright Blue)\",\n          \"colors\": [\"#05e643\"]\n        },\n        {\n          \"dmxRange\": [71, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 147 (Apricot)\",\n          \"colors\": [\"#cd7a0f\"]\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 148 (Bright Rose)\",\n          \"colors\": [\"#ff2320\"]\n        },\n        {\n          \"dmxRange\": [75, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 152 (Pale Gold)\",\n          \"colors\": [\"#da9e27\"]\n        },\n        {\n          \"dmxRange\": [77, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 154 (Pale Rose)\",\n          \"colors\": [\"#ffa22f\"]\n        },\n        {\n          \"dmxRange\": [79, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 157 (Pink)\",\n          \"colors\": [\"#ff5529\"]\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 158 (Deep Orange)\",\n          \"colors\": [\"#ff8700\"]\n        },\n        {\n          \"dmxRange\": [83, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 162 (Bastard Amber)\",\n          \"colors\": [\"#f7bd2a\"]\n        },\n        {\n          \"dmxRange\": [85, 86],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 164 (Flame Red)\",\n          \"colors\": [\"#ff1f04\"]\n        },\n        {\n          \"dmxRange\": [87, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 165 (Daylight Blue)\",\n          \"colors\": [\"#54ff8c\"]\n        },\n        {\n          \"dmxRange\": [89, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 169 (Lilac Tint)\",\n          \"colors\": [\"#ffc95f\"]\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 170 (Deep Lavender)\",\n          \"colors\": [\"#ff9649\"]\n        },\n        {\n          \"dmxRange\": [93, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 172 (Lagoon Blue)\",\n          \"colors\": [\"#05ff43\"]\n        },\n        {\n          \"dmxRange\": [95, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 179 (Chrome Orange)\",\n          \"colors\": [\"#ffbe00\"]\n        },\n        {\n          \"dmxRange\": [97, 98],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 180 (Dark Lavender)\",\n          \"colors\": [\"#d98aff\"]\n        },\n        {\n          \"dmxRange\": [99, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 181 (Congo Blue)\",\n          \"colors\": [\"#2009ff\"]\n        },\n        {\n          \"dmxRange\": [101, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 197 (Alice Blue)\",\n          \"colors\": [\"#73e5be\"]\n        },\n        {\n          \"dmxRange\": [103, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 201 (Full CT Blue)\",\n          \"colors\": [\"#d0ff95\"]\n        },\n        {\n          \"dmxRange\": [105, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 202 (Half CT Blue)\",\n          \"colors\": [\"#fffa67\"]\n        },\n        {\n          \"dmxRange\": [107, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 203 (Quarter CT Blue)\",\n          \"colors\": [\"#ffea69\"]\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 204 (Full CT Orange)\",\n          \"colors\": [\"#e98606\"]\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 205 (Half CT Orange)\",\n          \"colors\": [\"#fcd9b1\"]\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 206 (Quarter CT Orange)\",\n          \"colors\": [\"#ffd13b\"]\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 247 (Filter Minus Green)\",\n          \"colors\": [\"#ff996c\"]\n        },\n        {\n          \"dmxRange\": [117, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 248 (Half Minus Green)\",\n          \"colors\": [\"#ffae4e\"]\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 281 (Three Quarter CT Blue)\",\n          \"colors\": [\"#eeffa5\"]\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 285 (Three Quarter CT Orange)\",\n          \"colors\": [\"#c4880f\"]\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 352 (Glacier Blue)\",\n          \"colors\": [\"#5afb8b\"]\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 353 (Lighter Blue)\",\n          \"colors\": [\"#61d476\"]\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 715 (Cabana Blue)\",\n          \"colors\": [\"#3c6edc\"]\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 778 (Millennium Gold)\",\n          \"colors\": [\"#ff4100\"]\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Filter 793 (Vanity Fair)\",\n          \"colors\": [\"#ff0f1b\"]\n        },\n        {\n          \"dmxRange\": [133, 202],\n          \"type\": \"Generic\",\n          \"comment\": \"Multicolor\"\n        },\n        {\n          \"dmxRange\": [203, 215],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 1\"\n        },\n        {\n          \"dmxRange\": [218, 219],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 2\"\n        },\n        {\n          \"dmxRange\": [220, 221],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 3\"\n        },\n        {\n          \"dmxRange\": [222, 223],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 4\"\n        },\n        {\n          \"dmxRange\": [224, 225],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 5\"\n        },\n        {\n          \"dmxRange\": [226, 227],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 6\"\n        },\n        {\n          \"dmxRange\": [228, 229],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 7\"\n        },\n        {\n          \"dmxRange\": [230, 231],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 8\"\n        },\n        {\n          \"dmxRange\": [232, 233],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 9\"\n        },\n        {\n          \"dmxRange\": [234, 235],\n          \"type\": \"Generic\",\n          \"comment\": \"User color 10\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Generic\",\n          \"comment\": \"Rainbow effect (with fade time)\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Rainbow effect (without fade time)\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Cyan\": {\n      \"fineChannelAliases\": [\"Cyan fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"fineChannelAliases\": [\"Magenta fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"fineChannelAliases\": [\"Yellow fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Amber\": {\n      \"fineChannelAliases\": [\"Amber fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Light Green\": {\n      \"fineChannelAliases\": [\"Light Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Lime\"\n      }\n    },\n    \"CTC\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorTemperature\",\n        \"colorTemperatureStart\": \"8000K\",\n        \"colorTemperatureEnd\": \"2700K\"\n      }\n    },\n    \"Color Mix Mode\": {\n      \"defaultValue\": 45,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Virtual colors (Virtual has priority)\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Maximum mode (highest values have priority)\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Minimum mode (lowest values have priority)\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Multiply mode (multiply Virtual and Color Mix)\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Addition mode (Virtual + Color mix)\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Subtraction mode (Virtual - Color mix)\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Inverted Subtraction mode (Color mix - Virtual)\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"White Point Off\"\n        },\n        {\n          \"dmxRange\": [80, 128],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [129, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Virtual colors (virtual has priority)\"\n        },\n        {\n          \"dmxRange\": [130, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Crossfade (crossfade between Virtual and Color mix)\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color channels (Color mix has priority)\"\n        }\n      ]\n    },\n    \"Green Correction\": {\n      \"name\": \"Green Correction\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"-99%…-1%\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        },\n        {\n          \"dmxRange\": [129, 254],\n          \"type\": \"Generic\",\n          \"comment\": \"1%…99%\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Neutral\"\n        }\n      ]\n    },\n    \"Gobo Selection Rotation Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Rot. Gobo carousel/Framing shutters/Zoom/Focus/Iris/Frost/Prism time\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Effect wheel positioning\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Proportional indexing\"\n        },\n        {\n          \"dmxRange\": [128, 170],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Ramping from open to full position\"\n        },\n        {\n          \"dmxRange\": [171, 213],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Ramping from open to half position\"\n        },\n        {\n          \"dmxRange\": [214, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Ramping from half to full position\"\n        }\n      ]\n    },\n    \"Effect wheel rotation\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"Speed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"comment\": \"Forwards rotation from fast to slow\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Speed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"Backwards rotation from slow to fast\"\n        }\n      ]\n    },\n    \"Effect wheel animations\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No animation\"\n        },\n        {\n          \"dmxRange\": [8, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 1 (Focus=94)\"\n        },\n        {\n          \"dmxRange\": [10, 11],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 2 (Focus=84)\"\n        },\n        {\n          \"dmxRange\": [12, 13],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 3 (Focus=87)\"\n        },\n        {\n          \"dmxRange\": [14, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 4 (Focus=69)\"\n        },\n        {\n          \"dmxRange\": [16, 17],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 5 (Focus=82)\"\n        },\n        {\n          \"dmxRange\": [18, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 6 (Focus=82)\"\n        },\n        {\n          \"dmxRange\": [20, 21],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 7 (Focus=72)\"\n        },\n        {\n          \"dmxRange\": [22, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 8 (Focus=86)\"\n        },\n        {\n          \"dmxRange\": [24, 25],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 9 (Focus=78)\"\n        },\n        {\n          \"dmxRange\": [26, 27],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Macro 10 (Focus=102)\"\n        },\n        {\n          \"dmxRange\": [28, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotation\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Rotation\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Rotation fine\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [202, 222],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [223, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random Gobo selection by audio control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Random Gobo selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"switchChannels\": {\n            \"Rotating Gobo Control\": \"Rotating Gobo Indexing\",\n            \"Rotating Gobo Control fine\": \"Rotating Gobo Indexing fine\"\n          }\n        }\n      ]\n    },\n    \"Rotating Gobo Indexing\": {\n      \"fineChannelAliases\": [\"Rotating Gobo Indexing fine\"],\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Rotating Gobo Rotation\": {\n      \"fineChannelAliases\": [\"Rotating Gobo Rotation fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet rotating\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 16\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [1, 179],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"off\",\n          \"frostIntensityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        },\n        {\n          \"dmxRange\": [190, 211],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse closing\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [212, 233],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse opening\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramping\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"fineChannelAliases\": [\"Iris fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [1, 179],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"open\",\n          \"openPercentEnd\": \"closed\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [192, 219],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [220, 247],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 249],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random pulse opening\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 251],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random pulse opening\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [252, 253],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random pulse closing\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random pulse closing\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"49deg\",\n        \"angleEnd\": \"7deg\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Framing shutters module rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Rotation from right (0°) to 60°\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"Center\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Rotation from 60° to left (120°)\"\n        }\n      ]\n    },\n    \"Framing shutter 1-movement\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Movement from Outward to Inward\"\n      }\n    },\n    \"Framing shutter 1-swivelling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Swivelling from -30° towards 0°\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"0°\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Swivelling from 0° to +30°\"\n        }\n      ]\n    },\n    \"Framing shutter 2-movement\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Movement from Outward to Inward\"\n      }\n    },\n    \"Framing shutter 2-swivelling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Swivelling from -30° towards 0°\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"0°\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Swivelling from 0° to +30°\"\n        }\n      ]\n    },\n    \"Framing shutter 3-movement\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Movement from Outward to Inward\"\n      }\n    },\n    \"Framing shutter 3-swivelling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Swivelling from -30° towards 0°\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"0°\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Swivelling from 0° to +30°\"\n        }\n      ]\n    },\n    \"Framing shutter 4-movement\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Movement from Outward to Inward\"\n      }\n    },\n    \"Framing shutter 4-swivelling\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Swivelling from -30° towards 0°\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"Generic\",\n          \"comment\": \"0°\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Swivelling from 0° to +30°\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"comment\": \"Lamp power = 180W\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"15Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"comment\": \"Lamp power = 180W\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"CMY\",\n      \"shortName\": \"M1-CMY\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special Functions\",\n        \"LED Frequency\",\n        \"LED Frequency Adjustment\",\n        \"Color Functions\",\n        \"CRI Selection\",\n        \"Virtual Color wheel\",\n        \"Cyan\",\n        \"Cyan fine\",\n        \"Magenta\",\n        \"Magenta fine\",\n        \"Yellow\",\n        \"Yellow fine\",\n        \"CTC\",\n        \"Green Correction\",\n        \"Color Mix Mode\",\n        \"Gobo Selection Rotation Speed\",\n        \"Rot. Gobo carousel/Framing shutters/Zoom/Focus/Iris/Frost/Prism time\",\n        \"Effect wheel positioning\",\n        \"Effect wheel rotation\",\n        \"Effect wheel animations\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Control\",\n        \"Rotating Gobo Control fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Iris fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Framing shutters module rotation\",\n        \"Framing shutter 1-movement\",\n        \"Framing shutter 1-swivelling\",\n        \"Framing shutter 2-movement\",\n        \"Framing shutter 2-swivelling\",\n        \"Framing shutter 3-movement\",\n        \"Framing shutter 3-swivelling\",\n        \"Framing shutter 4-movement\",\n        \"Framing shutter 4-swivelling\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"M1-RGB\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special Functions\",\n        \"LED Frequency\",\n        \"LED Frequency Adjustment\",\n        \"Color Functions\",\n        \"CRI Selection\",\n        \"Virtual Color wheel\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"CTC\",\n        \"Green Correction\",\n        \"Color Mix Mode\",\n        \"Gobo Selection Rotation Speed\",\n        \"Rot. Gobo carousel/Framing shutters/Zoom/Focus/Iris/Frost/Prism time\",\n        \"Effect wheel positioning\",\n        \"Effect wheel rotation\",\n        \"Effect wheel animations\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Control\",\n        \"Rotating Gobo Control fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Iris fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Framing shutters module rotation\",\n        \"Framing shutter 1-movement\",\n        \"Framing shutter 1-swivelling\",\n        \"Framing shutter 2-movement\",\n        \"Framing shutter 2-swivelling\",\n        \"Framing shutter 3-movement\",\n        \"Framing shutter 3-swivelling\",\n        \"Framing shutter 4-movement\",\n        \"Framing shutter 4-swivelling\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"Reduced CMY\",\n      \"shortName\": \"M2-CMY\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special Functions\",\n        \"Color Functions\",\n        \"CRI Selection\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CTC\",\n        \"Effect wheel positioning\",\n        \"Effect wheel rotation\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Control\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Framing shutters module rotation\",\n        \"Framing shutter 1-movement\",\n        \"Framing shutter 1-swivelling\",\n        \"Framing shutter 2-movement\",\n        \"Framing shutter 2-swivelling\",\n        \"Framing shutter 3-movement\",\n        \"Framing shutter 3-swivelling\",\n        \"Framing shutter 4-movement\",\n        \"Framing shutter 4-swivelling\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Reduced RGB\",\n      \"shortName\": \"M2-RGB\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special Functions\",\n        \"Color Functions\",\n        \"CRI Selection\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"CTC\",\n        \"Effect wheel positioning\",\n        \"Effect wheel rotation\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Control\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Framing shutters module rotation\",\n        \"Framing shutter 1-movement\",\n        \"Framing shutter 1-swivelling\",\n        \"Framing shutter 2-movement\",\n        \"Framing shutter 2-swivelling\",\n        \"Framing shutter 3-movement\",\n        \"Framing shutter 3-swivelling\",\n        \"Framing shutter 4-movement\",\n        \"Framing shutter 4-swivelling\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"RGBA + Light Green\",\n      \"shortName\": \"M3\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Power/Special Functions\",\n        \"LED Frequency\",\n        \"LED Frequency Adjustment\",\n        \"Color Functions\",\n        \"CRI Selection\",\n        \"Virtual Color wheel\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"Amber\",\n        \"Amber fine\",\n        \"Light Green\",\n        \"Light Green fine\",\n        \"CTC\",\n        \"Green Correction\",\n        \"Color Mix Mode\",\n        \"Gobo Selection Rotation Speed\",\n        \"Rot. Gobo carousel/Framing shutters/Zoom/Focus/Iris/Frost/Prism time\",\n        \"Effect wheel positioning\",\n        \"Effect wheel rotation\",\n        \"Effect wheel animations\",\n        \"Rotating Gobo Wheel\",\n        \"Rotating Gobo Control\",\n        \"Rotating Gobo Control fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Iris fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Framing shutters module rotation\",\n        \"Framing shutter 1-movement\",\n        \"Framing shutter 1-swivelling\",\n        \"Framing shutter 2-movement\",\n        \"Framing shutter 2-swivelling\",\n        \"Framing shutter 3-movement\",\n        \"Framing shutter 3-swivelling\",\n        \"Framing shutter 4-movement\",\n        \"Framing shutter 4-swivelling\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/robin-viva-cmy.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ROBIN Viva CMY\",\n  \"shortName\": \"VivaCMY\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"JonahKr\"],\n    \"createDate\": \"2018-10-12\",\n    \"lastModifyDate\": \"2021-09-13\",\n    \"importPlugin\": {\n      \"plugin\": \"gdtf\",\n      \"date\": \"2018-10-24\",\n      \"comment\": \"GDTF fixture type ID: 80 29 d2 62 a7 13 46 0f be dc a7 42 20 8f c5 0d\"\n    }\n  },\n  \"comment\": \"Powerfully smooth, Robe’s VIVA CMY combines brightness of exceptionally clear zero-fringing white beam together with continuous color transitions of CMY mixing. \",\n  \"links\": {\n    \"manual\": [\n      \"https://www.robe.cz/api/support-files/download/downloads/user_manuals/User_manual_Robin_Viva_CMY.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robe.cz/viva-cmy\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2K1CvARI_Wc\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 203,\n    \"softwareVersion\": \"1.0\"\n  },\n  \"physical\": {\n    \"dimensions\": [380, 675, 250],\n    \"weight\": 19,\n    \"power\": 500,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"350W white\",\n      \"colorTemperature\": 6500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [9, 40]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Deep red\",\n          \"colors\": [\"#d0282f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00a650\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#f9d1aa\"],\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#faa649\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lavender\",\n          \"colors\": [\"#c6cbe6\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Congo blue\",\n          \"colors\": [\"#6863e1\"]\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1 (99014836-1)\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2 (99014836-2)\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3 (99014836-3)\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4 (99014836-4)\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5 (99014836-5)\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6 (99014836-6)\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 7 (99014836-7)\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 8 (99014836-8)\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 9 (99014836-9)\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Ornament\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Bubble Triangle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Whirls\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Pinwheel\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Abstract Squares\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Abstract Lines\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Lines With Wheels\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Standard mode\"\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [2, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"durationStart\": \"0.2s\",\n          \"durationEnd\": \"25.5s\",\n          \"comment\": \"fast…slow\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"DMX input: Wired DMX\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"DMX input: Wireless DMX\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Graphic display On\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Graphic display Off\"\n        },\n        {\n          \"dmxRange\": [30, 49],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer curve: Square law\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Dimmer curve: Linear\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fans mode: Auto\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Fans mode: High\"\n        },\n        {\n          \"dmxRange\": [70, 89],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pan/Tilt speed mode\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pan/Tilt time mode\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Blackout while pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Disabled blackout while pan/tilt moving\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Blackout while colour wheels moving\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Disabled blackout while colour wheels moving\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Pan/Tilt reset\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Colour system reset\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Gobo wheels + iris reset\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Zoom/focus/frost/prism reset\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Total reset\"\n        },\n        {\n          \"dmxRange\": [210, 239],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Disable Quiet mode\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"parameterStart\": \"low\",\n          \"parameterEnd\": \"high\",\n          \"comment\": \"Quiet mode - fan noise control\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"fineChannelAliases\": [\"Color Wheel fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [18, 18],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [19, 36],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [37, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [38, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [55, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [56, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [73, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [74, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [91, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [92, 108],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [109, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [110, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [128, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [190, 215],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [216, 217],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [218, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random colour selection\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random colour selection\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 4 (Medium Bastard Amber)\",\n          \"colors\": [\"#ffc8b4\"]\n        },\n        {\n          \"dmxRange\": [3, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 10 (Medium Yellow)\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 19 (Fire)\",\n          \"colors\": [\"#ff4600\"]\n        },\n        {\n          \"dmxRange\": [7, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 24 (Scarlet)\",\n          \"colors\": [\"#ff5a64\"]\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 58 (Lavender)\",\n          \"colors\": [\"#b46ef0\"]\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 68 (Sky Blue)\",\n          \"colors\": [\"#46b4f0\"]\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 71 (Tokyo Blue)\",\n          \"colors\": [\"#0000b4\"]\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 79 (Just Blue)\",\n          \"colors\": [\"#3c8cd2\"]\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 88 (Lime Green)\",\n          \"colors\": [\"#dcff64\"]\n        },\n        {\n          \"dmxRange\": [19, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 90 (Dark Yellow Green)\",\n          \"colors\": [\"#00be00\"]\n        },\n        {\n          \"dmxRange\": [21, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 100 (Spring Yellow)\",\n          \"colors\": [\"#f5ff00\"]\n        },\n        {\n          \"dmxRange\": [23, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 101 (Yellow)\",\n          \"colors\": [\"#fff500\"]\n        },\n        {\n          \"dmxRange\": [25, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 102 (Light Amber)\",\n          \"colors\": [\"#ffdc5f\"]\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 103 (Straw)\",\n          \"colors\": [\"#fceacc\"]\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lee 104 (Deep Amber)\",\n          \"colors\": [\"#ffdc00\"]\n        },\n        {\n          \"dmxRange\": [31, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 105 (Orange)\",\n          \"colors\": [\"#ffa000\"]\n        },\n        {\n          \"dmxRange\": [33, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 781 (Terry Red)\",\n          \"colors\": [\"#ff5000\"]\n        },\n        {\n          \"dmxRange\": [35, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 111 (Dark Pink)\",\n          \"colors\": [\"#ff8cbe\"]\n        },\n        {\n          \"dmxRange\": [37, 38],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 115 (Peacock Blue)\",\n          \"colors\": [\"#00ebc8\"]\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 505 (Sally Green)\",\n          \"colors\": [\"#e3ff5a\"]\n        },\n        {\n          \"dmxRange\": [41, 42],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 117 (Steel Blue)\",\n          \"colors\": [\"#b4faf5\"]\n        },\n        {\n          \"dmxRange\": [43, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 118 (Light Blue)\",\n          \"colors\": [\"#00e1eb\"]\n        },\n        {\n          \"dmxRange\": [45, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 724 (Ocean Blue)\",\n          \"colors\": [\"#69e1eb\"]\n        },\n        {\n          \"dmxRange\": [47, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 725 (Old Steel Blue\",\n          \"colors\": [\"#bef2f3\"]\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 121 (LEE Green)\",\n          \"colors\": [\"#b4ff64\"]\n        },\n        {\n          \"dmxRange\": [51, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 128 (Bright Pink)\",\n          \"colors\": [\"#ff50b4\"]\n        },\n        {\n          \"dmxRange\": [53, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 131 (Marine Blue)\",\n          \"colors\": [\"#64fad2\"]\n        },\n        {\n          \"dmxRange\": [55, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 132 (Medium Blue)\",\n          \"colors\": [\"#00a0dc\"]\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 134 (Golden Amber)\",\n          \"colors\": [\"#faa873\"]\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 135 (Deep Golden Amber)\",\n          \"colors\": [\"#ff5f00\"]\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 136 (Pale Lavender)\",\n          \"colors\": [\"#f0bee6\"]\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 137 (Special Lavender)\",\n          \"colors\": [\"#c8b4e6\"]\n        },\n        {\n          \"dmxRange\": [65, 66],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 138 (Pale Green)\",\n          \"colors\": [\"#dcffa0\"]\n        },\n        {\n          \"dmxRange\": [67, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 139 (Primary Green)\",\n          \"colors\": [\"#4bc300\"]\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 141 (Bright Blue)\",\n          \"colors\": [\"#00d2e6\"]\n        },\n        {\n          \"dmxRange\": [71, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 147 (Apricot)\",\n          \"colors\": [\"#fcb98c\"]\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 148 (Bright Rose)\",\n          \"colors\": [\"#ff507d\"]\n        },\n        {\n          \"dmxRange\": [75, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 152 (Pale Gold)\",\n          \"colors\": [\"#ffd2c1\"]\n        },\n        {\n          \"dmxRange\": [77, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 154 (Pale Rose)\",\n          \"colors\": [\"#ffd5cf\"]\n        },\n        {\n          \"dmxRange\": [79, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 157 (Pink)\",\n          \"colors\": [\"#ff92a3\"]\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 158 (Deep Orange)\",\n          \"colors\": [\"#ff8700\"]\n        },\n        {\n          \"dmxRange\": [83, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 162 (Bastard Amber)\",\n          \"colors\": [\"#fcded8\"]\n        },\n        {\n          \"dmxRange\": [85, 86],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 164 (Flame Red)\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [87, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 165 (Daylight Blue)\",\n          \"colors\": [\"#5ac8eb\"]\n        },\n        {\n          \"dmxRange\": [89, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 169 (Lilac Tint)\",\n          \"colors\": [\"#fadcf0\"]\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 170 (Deep Lavender)\",\n          \"colors\": [\"#e6aadc\"]\n        },\n        {\n          \"dmxRange\": [93, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 172 (Lagoon Blue)\",\n          \"colors\": [\"#00dcdc\"]\n        },\n        {\n          \"dmxRange\": [95, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 179 (Chrome Orange)\",\n          \"colors\": [\"#ffbe00\"]\n        },\n        {\n          \"dmxRange\": [97, 98],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 180 (Dark Lavender)\",\n          \"colors\": [\"#a064e6\"]\n        },\n        {\n          \"dmxRange\": [99, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 181 (Congo Blue)\",\n          \"colors\": [\"#5000aa\"]\n        },\n        {\n          \"dmxRange\": [101, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 197 (Alice Blue)\",\n          \"colors\": [\"#82aae6\"]\n        },\n        {\n          \"dmxRange\": [103, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 201 (Full CT Blue)\",\n          \"colors\": [\"#c3e1fa\"]\n        },\n        {\n          \"dmxRange\": [105, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 202 (Half CT Blue)\",\n          \"colors\": [\"#d7f0ff\"]\n        },\n        {\n          \"dmxRange\": [107, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 203 (Quarter CT Blue)\",\n          \"colors\": [\"#ebfcff\"]\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 204 (Full CT Orange)\",\n          \"colors\": [\"#fac387\"]\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 205 (Half CT Orange)\",\n          \"colors\": [\"#fcd9b1\"]\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 206 (Quarter CT Orange)\",\n          \"colors\": [\"#fcead6\"]\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 247 (LEE Minus Green)\",\n          \"colors\": [\"#fac3d7\"]\n        },\n        {\n          \"dmxRange\": [117, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 248 (Half Minus Green)\",\n          \"colors\": [\"#ffe2e4\"]\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 281 (Three Quarter CT Blue)\",\n          \"colors\": [\"#cde6fa\"]\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 285 (Three Quarter CT Orange)\",\n          \"colors\": [\"#fccd94\"]\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 352 (Glacier Blue)\",\n          \"colors\": [\"#5ac8e1\"]\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 353 (Lighter Blue)\",\n          \"colors\": [\"#61e8e3\"]\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 715 (Cabana Blue)\",\n          \"colors\": [\"#3c6edc\"]\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 778 (Millennium Gold)\",\n          \"colors\": [\"#ff7600\"]\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"LEE 328 (Follies Pink)\",\n          \"colors\": [\"#ff64c8\"]\n        },\n        {\n          \"dmxRange\": [133, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel + CMY Time\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"Time\",\n          \"timeStart\": \"0.1s\",\n          \"timeEnd\": \"25.5s\"\n        }\n      ]\n    },\n    \"Effect Time\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 50],\n          \"type\": \"Time\",\n          \"timeStart\": \"0.1s\",\n          \"timeEnd\": \"5s\",\n          \"comment\": \"Prism, stat. gobo, zoom, focus, iris, frost\"\n        },\n        {\n          \"dmxRange\": [51, 255],\n          \"type\": \"Time\",\n          \"timeStart\": \"5s\",\n          \"timeEnd\": \"25.5s\",\n          \"comment\": \"Stat. gobo, zoom, focus, iris, frost\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [27, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [36, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [45, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [54, 62],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [63, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [72, 80],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [81, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [92, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 115],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [116, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [140, 151],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [152, 163],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [164, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 187],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [188, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [202, 222],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [223, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Rotating Gobo Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8,\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"indexing\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Angle\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Angle fine\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"rotating\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 201],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1,\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [202, 222],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [223, 243],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random gobo\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"switchChannels\": {\n            \"Gobo Stencil Rotation\": \"Gobo Stencil Rotation Speed\",\n            \"Gobo Stencil Rotation fine\": \"Gobo Stencil Rotation Speed fine\"\n          }\n        }\n      ]\n    },\n    \"Gobo Stencil Rotation Angle\": {\n      \"fineChannelAliases\": [\"Gobo Stencil Rotation Angle fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"WheelSlotRotation\",\n        \"wheel\": \"Rotating Gobo Wheel\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Gobo Stencil Rotation Speed\": {\n      \"fineChannelAliases\": [\"Gobo Stencil Rotation Speed fine\"],\n      \"defaultValue\": 32896,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 32767],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [32768, 32768],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [32769, 65535],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotating Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet rotating\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 12\"\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 13\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 14\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 15\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"Macro 16\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"defaultValue\": 128,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PrismRotation\",\n          \"angle\": \"0deg\"\n        },\n        {\n          \"dmxRange\": [1, 127],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 128],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [1, 179],\n          \"type\": \"Frost\",\n          \"frostIntensityStart\": \"off\",\n          \"frostIntensityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        },\n        {\n          \"dmxRange\": [190, 211],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse closing\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [212, 233],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Pulse opening\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [234, 255],\n          \"type\": \"FrostEffect\",\n          \"effectName\": \"Ramping\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Iris\": {\n      \"fineChannelAliases\": [\"Iris fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"Iris\",\n          \"openPercent\": \"open\"\n        },\n        {\n          \"dmxRange\": [1, 179],\n          \"type\": \"Iris\",\n          \"openPercentStart\": \"open\",\n          \"openPercentEnd\": \"closed\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"Iris\",\n          \"openPercent\": \"closed\"\n        },\n        {\n          \"dmxRange\": [192, 219],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [220, 247],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 249],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random pulse opening\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 251],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random pulse opening\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [252, 253],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random pulse closing\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"IrisEffect\",\n          \"effectName\": \"Random pulse closing\",\n          \"speed\": \"slow\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"fineChannelAliases\": [\"Zoom fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"40deg\",\n        \"angleEnd\": \"9deg\"\n      }\n    },\n    \"Focus\": {\n      \"fineChannelAliases\": [\"Focus fine\"],\n      \"defaultValue\": 32896,\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Reserved\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Shutter\": {\n      \"defaultValue\": 32,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"15Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"15Hz\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"15Hz\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.1Hz\",\n          \"speedEnd\": \"15Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Standard 16 bit\",\n      \"shortName\": \"std\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Control\",\n        \"Color Wheel\",\n        \"Color Wheel fine\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Macros\",\n        \"Effect Speed\",\n        \"Color Wheel + CMY Time\",\n        \"Effect Time\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Gobo Stencil Rotation fine\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Iris fine\",\n        \"Zoom\",\n        \"Zoom fine\",\n        \"Focus\",\n        \"Focus fine\",\n        \"Reserved\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"Reduced 8 bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Control\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"Color Macros\",\n        \"Effect Speed\",\n        \"Color Wheel + CMY Time\",\n        \"Effect Time\",\n        \"Static Gobo Wheel\",\n        \"Rotating Gobo Wheel\",\n        \"Gobo Stencil Rotation\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Frost\",\n        \"Iris\",\n        \"Zoom\",\n        \"Focus\",\n        \"Reserved\",\n        \"Shutter\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robe/spot-160-xt.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Spot 160 XT\",\n  \"shortName\": \"RobeSpot160XT\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ringo333\"],\n    \"createDate\": \"2019-04-24\",\n    \"lastModifyDate\": \"2026-01-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.aesono.fr/manuel/Robe-Spot-160XT.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=rchX19BOlV0\"\n    ],\n    \"other\": [\n      \"https://spares.robe.cz/category/spot_160_xt\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [292, 415, 378],\n    \"weight\": 10.5,\n    \"power\": 300,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"Philips CDM-SA/T150W/942\",\n      \"colorTemperature\": 4200,\n      \"lumens\": 14000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [19, 19]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Turquoise\",\n          \"colors\": [\"#00ffaa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light green\",\n          \"colors\": [\"#aaffaa\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#00ccff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ffaacc\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ffaa00\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"530deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"280deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [1, 249],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"helpWanted\": \"Is it slow…fast or fast…slow?\"\n        },\n        {\n          \"dmxRange\": [250, 252],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on color/gobo change\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on pan/tilt/color/gobo change\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [1, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [21, 21],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [22, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [32, 32],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [33, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [42, 42],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [43, 52],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [53, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [54, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [64, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [65, 73],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [74, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [75, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [85, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [96, 96],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [97, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 10,\n          \"slotNumberEnd\": 11\n        },\n        {\n          \"dmxRange\": [106, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [107, 116],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 11,\n          \"slotNumberEnd\": 12\n        },\n        {\n          \"dmxRange\": [117, 117],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 12,\n          \"slotNumberEnd\": 13\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [96, 115],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [116, 135],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [136, 155],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [156, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 195],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [196, 215],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [216, 235],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Dimmer / Shutter / Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [1, 63],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [128, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset, shutter closed\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1st\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Dimmer / Shutter / Reset\"\n      ]\n    },\n    {\n      \"name\": \"2nd\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Dimmer / Shutter / Reset\"\n      ]\n    },\n    {\n      \"name\": \"3rd\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Dimmer / Shutter / Reset\"\n      ]\n    },\n    {\n      \"name\": \"4th\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Dimmer / Shutter / Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/robert-juliat/613sx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"613SX\",\n  \"shortName\": \"RJ613SX\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"dariovideo\"],\n    \"createDate\": \"2018-11-27\",\n    \"lastModifyDate\": \"2018-11-27\"\n  },\n  \"comment\": \"Only controllable via dimmer pack\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.robertjuliat.com/Product_Specifications/Fiches_EN/Standard/DSEN045_613SX.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.robertjuliat.com/profilespots/600SX.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [330, 415, 565],\n    \"weight\": 11,\n    \"power\": 1000,\n    \"bulb\": {\n      \"type\": \"Tungsten T19\",\n      \"colorTemperature\": 3050,\n      \"lumens\": 21000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [28, 54]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Dimmer\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/rockville/rockpar50.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RockPAR50\",\n  \"shortName\": \"RockvilleRockPAR50\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Jeff Kowalik\"],\n    \"createDate\": \"2019-05-03\",\n    \"lastModifyDate\": \"2019-05-03\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.rockvilleaudio.com/rockpar50/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=E4kI6QuNiMg\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [185, 178, 110],\n    \"power\": 24,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18x 1W LEDs (6x red, 6x green, 6x blue)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": \"0%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Effects\": {\n      \"defaultValue\": \"0%\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 101],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"switchChannels\": {\n            \"Speed\": \"Strobe Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-activated\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed\": \"Effect Speed\"\n          }\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe Speed\": {\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6 Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Effects\",\n        \"Speed\"\n      ]\n    },\n    {\n      \"name\": \"3 Channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/sgm/p-5.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"P-5\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Matthias Schlecht\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-03-28\",\n    \"lastModifyDate\": \"2020-03-28\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2020-03-28\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.3 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://sgmlight.com/Files/Files/Perfion/StrRDDATAUserManualFileGroup/P-5/FileRDDATAUserManualP5SeriesWEB/SGM%20P-5%20Series%20User%20Manual%20STD%20and%20POI%20(Rev.%20J).pdf\",\n      \"https://sgmlight.com/Files/Files/Perfion/StrRDDATADMXFileGroup/P-5%20RGBW/FileRDDATADMXChartsP5RGBWRnD/DMX_Protocol_P_5_Rev4.pdf\"\n    ],\n    \"productPage\": [\n      \"https://sgmlight.com/products/entertainment/p%c2%b75\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=xu1JQjSibV0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [497, 268, 122],\n    \"weight\": 8.9,\n    \"power\": 450,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"44× 10W RGBW LEDs\",\n      \"lumens\": 20031\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 43]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Intensity\": {\n      \"fineChannelAliases\": [\"Intensity fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"CTC\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [1, 4],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"default\",\n          \"comment\": \"Raw\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2000K\",\n          \"colorTemperatureEnd\": \"10000K\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 151],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [152, 175],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 244],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [245, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel (Full Color Calibrated)\",\n      \"shortName\": \"3ch-calibrated\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel (RAW)\",\n      \"shortName\": \"4ch-raw\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel (RAW)\",\n      \"shortName\": \"6ch-raw\",\n      \"channels\": [\n        \"Shutter\",\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel (CTC)\",\n      \"shortName\": \"6ch-ctc\",\n      \"channels\": [\n        \"Shutter\",\n        \"Intensity\",\n        \"CTC\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"8-channel (RAW) 16bit\",\n      \"shortName\": \"8ch-raw 16bit\",\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"9-channel (RAW) 16bit\",\n      \"shortName\": \"9ch-raw 16bit\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"10-channel (RAW) 16bit\",\n      \"shortName\": \"10ch-raw 16bit\",\n      \"channels\": [\n        \"Intensity\",\n        \"Intensity fine\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"10-channel (CTC)\",\n      \"shortName\": \"10ch-ctc\",\n      \"channels\": [\n        \"Shutter\",\n        \"Intensity\",\n        \"Intensity fine\",\n        \"CTC\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/shehds/led-flat-par-12x3w-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Flat Par 12x3W RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Potatoe\", \"JonahKr\"],\n    \"createDate\": \"2018-11-11\",\n    \"lastModifyDate\": \"2023-02-12\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://web.archive.org/web/20220928042132/https://www.shehds.com/led-par-12x3w-rgbw-led-stage-light-par-light-with-dmx512-for-disco-dj-party-decoration-stage-lighting-p0087.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [118, 105, 114],\n    \"weight\": 0.35,\n    \"power\": 36,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x3W LEDs (3 red, 3 green, 3 blue, 3 white)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color pulse\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Function speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Program\",\n        \"Function speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/shehds/led-flat-par-18x18w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Flat Par 18x18W\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"V. Mateev\"],\n    \"createDate\": \"2022-10-18\",\n    \"lastModifyDate\": \"2026-01-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://drive.google.com/drive/folders/1gWrldZzcXsxee5q9pLCC0LkAPH8Q0Yix?usp=sharing\"\n    ],\n    \"productPage\": [\n      \"https://shehds.com/products/aluminum-alloy-led-flat-par-18x18w-lighting-dj-par-cans-dmx-512-light-wash-stage-lighting\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=k7ynAEIPEuE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 115, 265],\n    \"weight\": 4,\n    \"power\": 324,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18x18W LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Pulse\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Function Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Program\",\n        \"Function Speed\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/shehds/led-flat-par-54x3w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Flat Par 54x3W\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"J2M\"],\n    \"createDate\": \"2022-10-21\",\n    \"lastModifyDate\": \"2022-10-21\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2022-10-12\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.6)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://web.archive.org/web/20220928033751/https://www.shehds.com/u_file/1908/file/4109b920cd.pdf\"\n    ],\n    \"productPage\": [\n      \"https://shehds.com/products/fast-shipping-led-54x3w-rgbw-led-flat-par-rgbw-color-mixing-dj-wash-light-stage-uplighting-ktv-disco-dj-dmx512\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Pv0_x9BYBug\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [260, 280, 130],\n    \"weight\": 0.4,\n    \"power\": 162,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Master dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program pulse\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Open sound control function\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"10Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Program\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/shehds/led-flat-par-7x18w-rgbwa-uv-light.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Flat Par 7x18W RGBWA+UV Light\",\n  \"categories\": [\"Color Changer\"],\n  \"comment\": \"There may be multiple variants of this fixture with similar profiles. See https://github.com/OpenLightingProject/open-fixture-library/pull/2204 for more information.\",\n  \"meta\": {\n    \"authors\": [\"jms27000\", \"René Bütikofer\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-11-02\",\n    \"lastModifyDate\": \"2023-02-05\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2021-10-16\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.4)\"\n    }\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://shehds.com/products/led-flat-par-7x12w-7x18w-rgbwauv-lighting\"\n    ],\n    \"manual\": [\n      \"https://web.archive.org/web/20221023054132/https://www.shehds.com/u_file/1907/file/45918ab3df.pdf\",\n      \"https://github.com/user-attachments/files/19477036/SHEHDS.LED.Flat.Par.7x18W.RGBWA%2BUV.Light.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [176, 178, 113],\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"power\": 126,\n    \"weight\": 0.9\n  },\n  \"availableChannels\": {\n    \"Master dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Violet\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Function Speed / Color Presets\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static color\",\n          \"switchChannels\": {\n            \"Function Speed / Color Presets\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Random colors\",\n          \"switchChannels\": {\n            \"Function Speed / Color Presets\": \"Function Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Random colors\",\n          \"switchChannels\": {\n            \"Function Speed / Color Presets\": \"Function Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Random colors, fade to black\",\n          \"switchChannels\": {\n            \"Function Speed / Color Presets\": \"Function Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"soundControlled\": true,\n          \"effectName\": \"Sound Mode\",\n          \"comment\": \"Static color flashing on beat\",\n          \"switchChannels\": {\n            \"Function Speed / Color Presets\": \"Color Presets\"\n          }\n        }\n      ]\n    },\n    \"Function Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#fff6da\"]\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Violet\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Violet\",\n        \"Function\",\n        \"Function Speed / Color Presets\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Master dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Violet\",\n        \"Strobe\",\n        \"Function\",\n        \"Function Speed / Color Presets\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/shehds/led-par-18x18w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Par 18x18W\",\n  \"shortName\": \"SheHds18x18\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Jay3\"],\n    \"createDate\": \"2022-11-06\",\n    \"lastModifyDate\": \"2022-11-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://ueeshop.ly200-cdn.com/u_file/UPAG/UPAG904/1912/file/c80fe135df.pdf\"\n    ],\n    \"productPage\": [\n      \"https://shehds.com/products/aluminum-alloy-led-flat-par-18x18w-lighting-dj-par-cans-dmx-512-light-wash-stage-lighting\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=k7ynAEIPEuE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 265, 115],\n    \"weight\": 3.15,\n    \"power\": 324,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"10Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Pulse\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/shehds/led-spot-60w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Spot 60W\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"yids\"],\n    \"createDate\": \"2022-11-14\",\n    \"lastModifyDate\": \"2023-04-20\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2022-11-08\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.3)\"\n    }\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://shehds.com/products/good-technology-led-60w-gobos-moving-head-lighting-for-dmx512-stage-effect-dj-festivals-disco-home-entertainments-in-9-11-channels\"\n    ],\n    \"manual\": [\n      \"https://ueeshop.ly200-cdn.com/u_file/UPAG/UPAG904/2005/file/f56ea62fb9.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2ob8XVgcoRw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [198, 272, 144],\n    \"weight\": 3.2,\n    \"power\": 60,\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"wheels\": {\n    \"Color wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ed7d31\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lemon Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00b050\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#2e75b6\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#e98cc9\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Sky Blue\",\n          \"colors\": [\"#00b0f0\"]\n        }\n      ]\n    },\n    \"Gobo wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Rose\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Radial Dots\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Triangle\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Hexagon\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Swirl\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Swirl\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Jigsaw\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is this the correct effect and speed?\"\n        }\n      ]\n    },\n    \"Gobo wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"isShaking\": \"slot\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"isShaking\": \"slot\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"isShaking\": \"slot\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"isShaking\": \"slot\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"isShaking\": \"slot\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"isShaking\": \"slot\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"isShaking\": \"slot\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"helpWanted\": \"Is this the correct effect and speed?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"10Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Pan/Tilt speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Auto\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 48],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [49, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode 1\"\n        },\n        {\n          \"dmxRange\": [100, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode 2\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"soundControlled\": true,\n          \"effectName\": \"Sound Mode\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color wheel\",\n        \"Gobo wheel\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt speed\",\n        \"Auto\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color wheel\",\n        \"Gobo wheel\",\n        \"Strobe\",\n        \"Dimmer\",\n        \"Pan/Tilt speed\",\n        \"Auto\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showline/sl-nitro-510c.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SL NITRO 510C\",\n  \"shortName\": \"SLNitro510C\",\n  \"categories\": [\"Strobe\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Sebastian Portilla\", \"Felix Edelmann\"],\n    \"createDate\": \"2019-10-02\",\n    \"lastModifyDate\": \"2019-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.vari-lite.com/b-dam/vari-lite/products/sl-nitro-510c/guides-and-manuals/Selecon_SL_NITRO_510C_UserManual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.vari-lite.com/global/products/sl-nitro-510c\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_4WexFvyAR8&t=383\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [390, 103, 263],\n    \"weight\": 8,\n    \"power\": 360,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"264× RGB SMD LEDs, 264× white SMD LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [120, 120]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Zone 1\", \"Zone 2\", \"Zone 3\"],\n        [\"Zone 4\", \"Zone 5\", \"Zone 6\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"All Zones\": \"all\",\n      \"Top Row\": [\"Zone 1\", \"Zone 2\", \"Zone 3\"],\n      \"Bottom Row\": [\"Zone 4\", \"Zone 5\", \"Zone 6\"],\n      \"Left Zone\": [\"Zone 1\", \"Zone 4\"],\n      \"Center Zone\": [\"Zone 2\", \"Zone 5\"],\n      \"Right Zone\": [\"Zone 3\", \"Zone 6\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"fineChannelAliases\": [\"Master Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 0 (off)\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [7, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 1\"\n        },\n        {\n          \"dmxRange\": [9, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 2\"\n        },\n        {\n          \"dmxRange\": [11, 12],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 3\"\n        },\n        {\n          \"dmxRange\": [13, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 4\"\n        },\n        {\n          \"dmxRange\": [15, 16],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 5\"\n        },\n        {\n          \"dmxRange\": [17, 18],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 6\"\n        },\n        {\n          \"dmxRange\": [19, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 7\"\n        },\n        {\n          \"dmxRange\": [21, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 8\"\n        },\n        {\n          \"dmxRange\": [23, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 9\"\n        },\n        {\n          \"dmxRange\": [25, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 10\"\n        },\n        {\n          \"dmxRange\": [27, 28],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 11\"\n        },\n        {\n          \"dmxRange\": [29, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 12\"\n        },\n        {\n          \"dmxRange\": [31, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 13\"\n        },\n        {\n          \"dmxRange\": [33, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 14\"\n        },\n        {\n          \"dmxRange\": [35, 36],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 15\"\n        },\n        {\n          \"dmxRange\": [37, 38],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 16\"\n        },\n        {\n          \"dmxRange\": [39, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 17\"\n        },\n        {\n          \"dmxRange\": [41, 42],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 18\"\n        },\n        {\n          \"dmxRange\": [43, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 19\"\n        },\n        {\n          \"dmxRange\": [45, 46],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 20\"\n        },\n        {\n          \"dmxRange\": [47, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 21\"\n        },\n        {\n          \"dmxRange\": [49, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 22\"\n        },\n        {\n          \"dmxRange\": [51, 52],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 23\"\n        },\n        {\n          \"dmxRange\": [53, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 24\"\n        },\n        {\n          \"dmxRange\": [55, 56],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 25\"\n        },\n        {\n          \"dmxRange\": [57, 58],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 26\"\n        },\n        {\n          \"dmxRange\": [59, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 27\"\n        },\n        {\n          \"dmxRange\": [61, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 28\"\n        },\n        {\n          \"dmxRange\": [63, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 29\"\n        },\n        {\n          \"dmxRange\": [65, 66],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 30\"\n        },\n        {\n          \"dmxRange\": [67, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Preset 31\"\n        },\n        {\n          \"dmxRange\": [69, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_0 Color off\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [71, 72],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_1 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"10000K\"\n        },\n        {\n          \"dmxRange\": [73, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_2 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [75, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_3 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [77, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_4 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [79, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_5 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [81, 82],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_6 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4500K\"\n        },\n        {\n          \"dmxRange\": [83, 84],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_7 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [85, 86],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_8 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [87, 88],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_9 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"dmxRange\": [89, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_10 White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [91, 92],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_11 Moroccan Pink\"\n        },\n        {\n          \"dmxRange\": [93, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_12 Pink\"\n        },\n        {\n          \"dmxRange\": [95, 96],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_13 Flesh Pink\"\n        },\n        {\n          \"dmxRange\": [97, 98],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_14 Bright Rose\"\n        },\n        {\n          \"dmxRange\": [99, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_15 Follies Pink\"\n        },\n        {\n          \"dmxRange\": [101, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_16 Fuchsia Pink\"\n        },\n        {\n          \"dmxRange\": [103, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_17 Surprise Pink\"\n        },\n        {\n          \"dmxRange\": [105, 106],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_18 Congo Blue\"\n        },\n        {\n          \"dmxRange\": [107, 108],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_19 Blue\"\n        },\n        {\n          \"dmxRange\": [109, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_20 Virgin Blue\"\n        },\n        {\n          \"dmxRange\": [111, 112],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_21 Midnight Maya\"\n        },\n        {\n          \"dmxRange\": [113, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_22 Double C.T Blue\"\n        },\n        {\n          \"dmxRange\": [115, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_23 Slate Blue\"\n        },\n        {\n          \"dmxRange\": [117, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_24 Regal Blue\"\n        },\n        {\n          \"dmxRange\": [119, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_25 Full C.T Blue\"\n        },\n        {\n          \"dmxRange\": [121, 122],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_26 Steel Blue\"\n        },\n        {\n          \"dmxRange\": [123, 124],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_27 Lighter Blue\"\n        },\n        {\n          \"dmxRange\": [125, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_28 Cyan\"\n        },\n        {\n          \"dmxRange\": [127, 128],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_29 Marine Blue\"\n        },\n        {\n          \"dmxRange\": [129, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_30 Soft Green\"\n        },\n        {\n          \"dmxRange\": [131, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_31 Moss Green\"\n        },\n        {\n          \"dmxRange\": [133, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_32 Green\"\n        },\n        {\n          \"dmxRange\": [135, 136],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_33 Fem Green\"\n        },\n        {\n          \"dmxRange\": [137, 138],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_34 JAS Green\"\n        },\n        {\n          \"dmxRange\": [139, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_35 Pale Green\"\n        },\n        {\n          \"dmxRange\": [141, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_36 Spring Yellow\"\n        },\n        {\n          \"dmxRange\": [143, 144],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_37 Yellow\"\n        },\n        {\n          \"dmxRange\": [145, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_38 Deep Amber\"\n        },\n        {\n          \"dmxRange\": [147, 148],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_39 Chrome Orange\"\n        },\n        {\n          \"dmxRange\": [149, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_40 Orange\"\n        },\n        {\n          \"dmxRange\": [151, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_41 Magenta\"\n        },\n        {\n          \"dmxRange\": [153, 154],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_42 Flame Red\"\n        },\n        {\n          \"dmxRange\": [155, 156],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"CF_43 Purple\"\n        },\n        {\n          \"dmxRange\": [157, 171],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [172, 186],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        },\n        {\n          \"dmxRange\": [187, 201],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random color\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [202, 204],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 1\"\n        },\n        {\n          \"dmxRange\": [205, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 2\"\n        },\n        {\n          \"dmxRange\": [208, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 3\"\n        },\n        {\n          \"dmxRange\": [211, 213],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 4\"\n        },\n        {\n          \"dmxRange\": [214, 216],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 5\"\n        },\n        {\n          \"dmxRange\": [217, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 6\"\n        },\n        {\n          \"dmxRange\": [220, 222],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 7\"\n        },\n        {\n          \"dmxRange\": [223, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 8\"\n        },\n        {\n          \"dmxRange\": [226, 228],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 9\"\n        },\n        {\n          \"dmxRange\": [229, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Chase 10\"\n        },\n        {\n          \"dmxRange\": [232, 234],\n          \"type\": \"Effect\",\n          \"effectName\": \"User Chase 1\"\n        },\n        {\n          \"dmxRange\": [235, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"User Chase 2\"\n        },\n        {\n          \"dmxRange\": [238, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"User Chase 3\"\n        },\n        {\n          \"dmxRange\": [241, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"User Chase 4\"\n        },\n        {\n          \"dmxRange\": [244, 246],\n          \"type\": \"Effect\",\n          \"effectName\": \"User Chase 5\"\n        },\n        {\n          \"dmxRange\": [247, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"User Chase 6\"\n        },\n        {\n          \"dmxRange\": [250, 252],\n          \"type\": \"Effect\",\n          \"effectName\": \"User Chase 7\"\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"User Chase 8\"\n        }\n      ]\n    },\n    \"Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"8364ms\"\n      }\n    },\n    \"Strobe Rate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash when intensity > 5\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"30.488Hz\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 42],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [43, 85],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [86, 128],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [129, 171],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [172, 173],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Top row only\"\n        },\n        {\n          \"dmxRange\": [174, 175],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Bottom row only\"\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Left zone only\"\n        },\n        {\n          \"dmxRange\": [179, 180],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Center zone only\"\n        },\n        {\n          \"dmxRange\": [181, 182],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Right zone only\"\n        },\n        {\n          \"dmxRange\": [183, 184],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Checker pattern A\"\n        },\n        {\n          \"dmxRange\": [185, 186],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Checker pattern B\"\n        },\n        {\n          \"dmxRange\": [187, 214],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Random zones\"\n        },\n        {\n          \"dmxRange\": [215, 235],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Circle zone chase CW\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Circle zone chase CCW\"\n        }\n      ]\n    },\n    \"Intensity Timing\": {\n      \"defaultValue\": 255,\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"long\",\n        \"timeEnd\": \"instant\"\n      }\n    },\n    \"Color Timing\": {\n      \"defaultValue\": 255,\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"long\",\n        \"timeEnd\": \"instant\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default settings\"\n        },\n        {\n          \"dmxRange\": [5, 29],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve linear\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve square\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve S-curve\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer curve PL-curve\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [50, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Calibration off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Calibration on\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan off\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Combined zone control\"\n        },\n        {\n          \"dmxRange\": [105, 108],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear pattern\"\n        },\n        {\n          \"dmxRange\": [109, 112],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Checker pattern\"\n        },\n        {\n          \"dmxRange\": [113, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Reserved\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"$pixelKey Red\": {\n      \"fineChannelAliases\": [\"$pixelKey Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"fineChannelAliases\": [\"$pixelKey Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"fineChannelAliases\": [\"$pixelKey Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"fineChannelAliases\": [\"$pixelKey White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"8364ms\"\n      }\n    },\n    \"$pixelKey Strobe Rate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash when intensity > 5\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"30.488Hz\"\n        }\n      ]\n    },\n    \"$pixelKey Red Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"8364ms\"\n      }\n    },\n    \"$pixelKey Red Strobe Rate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash when intensity > 5\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"30.488Hz\"\n        }\n      ]\n    },\n    \"$pixelKey Green Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"8364ms\"\n      }\n    },\n    \"$pixelKey Green Strobe Rate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash when intensity > 5\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"30.488Hz\"\n        }\n      ]\n    },\n    \"$pixelKey Blue Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"8364ms\"\n      }\n    },\n    \"$pixelKey Blue Strobe Rate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash when intensity > 5\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"30.488Hz\"\n        }\n      ]\n    },\n    \"$pixelKey RGB Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"8364ms\"\n      }\n    },\n    \"$pixelKey RGB Strobe Rate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash when intensity > 5\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"30.488Hz\"\n        }\n      ]\n    },\n    \"$pixelKey White Strobe Duration\": {\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"8364ms\"\n      }\n    },\n    \"$pixelKey White Strobe Rate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Single flash when intensity > 5\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"30.488Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGBW Full 1-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"All Zones\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey Red Strobe Duration\",\n            \"$pixelKey Red Strobe Rate\",\n            \"$pixelKey Green Strobe Duration\",\n            \"$pixelKey Green Strobe Rate\",\n            \"$pixelKey Blue Strobe Duration\",\n            \"$pixelKey Blue Strobe Rate\",\n            \"$pixelKey White Strobe Duration\",\n            \"$pixelKey White Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW Full 2-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Top Row\", \"Bottom Row\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey Red Strobe Duration\",\n            \"$pixelKey Red Strobe Rate\",\n            \"$pixelKey Green Strobe Duration\",\n            \"$pixelKey Green Strobe Rate\",\n            \"$pixelKey Blue Strobe Duration\",\n            \"$pixelKey Blue Strobe Rate\",\n            \"$pixelKey White Strobe Duration\",\n            \"$pixelKey White Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW Full 3-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Left Zone\", \"Center Zone\", \"Right Zone\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey Red Strobe Duration\",\n            \"$pixelKey Red Strobe Rate\",\n            \"$pixelKey Green Strobe Duration\",\n            \"$pixelKey Green Strobe Rate\",\n            \"$pixelKey Blue Strobe Duration\",\n            \"$pixelKey Blue Strobe Rate\",\n            \"$pixelKey White Strobe Duration\",\n            \"$pixelKey White Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW Full 6-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey Red Strobe Duration\",\n            \"$pixelKey Red Strobe Rate\",\n            \"$pixelKey Green Strobe Duration\",\n            \"$pixelKey Green Strobe Rate\",\n            \"$pixelKey Blue Strobe Duration\",\n            \"$pixelKey Blue Strobe Rate\",\n            \"$pixelKey White Strobe Duration\",\n            \"$pixelKey White Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW Expanded 1-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"All Zones\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey RGB Strobe Duration\",\n            \"$pixelKey RGB Strobe Rate\",\n            \"$pixelKey White Strobe Duration\",\n            \"$pixelKey White Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW Expanded 2-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Top Row\", \"Bottom Row\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey RGB Strobe Duration\",\n            \"$pixelKey RGB Strobe Rate\",\n            \"$pixelKey White Strobe Duration\",\n            \"$pixelKey White Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW Expanded 3-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Left Zone\", \"Center Zone\", \"Right Zone\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey RGB Strobe Duration\",\n            \"$pixelKey RGB Strobe Rate\",\n            \"$pixelKey White Strobe Duration\",\n            \"$pixelKey White Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW Expanded 6-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey RGB Strobe Duration\",\n            \"$pixelKey RGB Strobe Rate\",\n            \"$pixelKey White Strobe Duration\",\n            \"$pixelKey White Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW 16-Bit 1-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"All Zones\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey Strobe Duration\",\n            \"$pixelKey Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW 16-Bit 2-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Top Row\", \"Bottom Row\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey Strobe Duration\",\n            \"$pixelKey Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW 16-Bit 3-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Left Zone\", \"Center Zone\", \"Right Zone\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey Strobe Duration\",\n            \"$pixelKey Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW 16-Bit 6-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Color Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\",\n            \"$pixelKey Strobe Duration\",\n            \"$pixelKey Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW 8-Bit 1-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"All Zones\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\",\n            \"$pixelKey Strobe Duration\",\n            \"$pixelKey Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW 8-Bit 2-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Top Row\", \"Bottom Row\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\",\n            \"$pixelKey Strobe Duration\",\n            \"$pixelKey Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW 8-Bit 3-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Left Zone\", \"Center Zone\", \"Right Zone\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\",\n            \"$pixelKey Strobe Duration\",\n            \"$pixelKey Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBW 8-Bit 6-zone\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Color Macros\",\n        \"Strobe\",\n        \"Intensity Timing\",\n        \"Control\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Intensity\",\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\",\n            \"$pixelKey Strobe Duration\",\n            \"$pixelKey Strobe Rate\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Color Macros\",\n        \"Strobe Duration\",\n        \"Strobe Rate\",\n        \"Strobe\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Mapping 16-Bit\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Red fine\",\n            \"$pixelKey Green\",\n            \"$pixelKey Green fine\",\n            \"$pixelKey Blue\",\n            \"$pixelKey Blue fine\",\n            \"$pixelKey White\",\n            \"$pixelKey White fine\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showlite/lb-4390.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LB-4390\",\n  \"categories\": [\"Stand\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\"],\n    \"createDate\": \"2020-07-20\",\n    \"lastModifyDate\": \"2020-07-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.kirstein.de/docs/manuals/sl-lb4390-en-0615.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.kirstein.de/en/Live-Studio/Light/Lighting-systems/Showlite-LB-4390-LED-complete-system-RGB-light-system.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1032, 235, 71],\n    \"weight\": 10.2,\n    \"power\": 84,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12× 9W RGB LEDs, 4× 1W white LEDs\",\n      \"lumens\": 100\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Flash 1\", \"Flash 2\", \"Flash 3\", \"Flash 4\"],\n        [ \"PAR 1\",   \"PAR 2\",   \"PAR 3\",   \"PAR 4\" ]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Flash LEDs\": [\"Flash 1\", \"Flash 2\", \"Flash 3\", \"Flash 4\"],\n      \"PAR LEDs\": [\"PAR 1\", \"PAR 2\", \"PAR 3\", \"PAR 4\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 10,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\",\n          \"comment\": \"Blackout\",\n          \"switchChannels\": {\n            \"Program\": \"Auto PAR Show\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show\",\n          \"switchChannels\": {\n            \"Program\": \"Auto PAR Show\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show\",\n          \"switchChannels\": {\n            \"Program\": \"Auto LED Flash Show\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix Auto Show\",\n          \"switchChannels\": {\n            \"Program\": \"Mix Auto Show\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program\": \"Sound PAR Show\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program\": \"Sound LED Flash Show\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix Sound Show\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program\": \"Mix Sound Show\"\n          }\n        }\n      ]\n    },\n    \"Auto PAR Show\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 1\"\n        },\n        {\n          \"dmxRange\": [15, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 2\"\n        },\n        {\n          \"dmxRange\": [30, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 3\"\n        },\n        {\n          \"dmxRange\": [45, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 4\"\n        },\n        {\n          \"dmxRange\": [60, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 5\"\n        },\n        {\n          \"dmxRange\": [75, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 6\"\n        },\n        {\n          \"dmxRange\": [90, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 7\"\n        },\n        {\n          \"dmxRange\": [105, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 8\"\n        },\n        {\n          \"dmxRange\": [120, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 9\"\n        },\n        {\n          \"dmxRange\": [135, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 10\"\n        },\n        {\n          \"dmxRange\": [150, 164],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 11\"\n        },\n        {\n          \"dmxRange\": [165, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 12\"\n        },\n        {\n          \"dmxRange\": [180, 194],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 13\"\n        },\n        {\n          \"dmxRange\": [195, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 14\"\n        },\n        {\n          \"dmxRange\": [210, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 15\"\n        },\n        {\n          \"dmxRange\": [225, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 16\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto PAR Show 17\"\n        }\n      ]\n    },\n    \"Auto LED Flash Show\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 1\"\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 2\"\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 3\"\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 4\"\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 5\"\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 6\"\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 7\"\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 8\"\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 9\"\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto LED Flash Show 10\"\n        }\n      ]\n    },\n    \"Mix Auto Show\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix Auto Show 1\"\n        },\n        {\n          \"dmxRange\": [100, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix Auto Show 2\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix Auto Show 3\"\n        }\n      ]\n    },\n    \"Sound PAR Show\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound PAR Show 12\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Sound LED Flash Show\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound LED Flash Show 10\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Mix Sound Show\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix Sound Show 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [100, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix Sound Show 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Mix Sound Show 3\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 191],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [192, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true,\n          \"comment\": \"PAR LEDs\"\n        },\n        {\n          \"dmxRange\": [201, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"comment\": \"PAR LEDs\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\",\n          \"comment\": \"All on\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [3, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"$pixelKey Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [3, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"$pixelKey Sound Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [3, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true,\n          \"helpWanted\": \"Can the strobe speed be controlled?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Program\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"5ch\",\n      \"channels\": [\n        \"Red PAR LEDs\",\n        \"Green PAR LEDs\",\n        \"Blue PAR LEDs\",\n        \"Dimmer / Strobe\",\n        \"Flash LEDs Sound Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"PAR 1\", \"PAR 2\", \"PAR 3\", \"PAR 4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"12ch (LED on)\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"PAR 1\", \"PAR 2\", \"PAR 3\", \"PAR 4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"24ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"PAR 1\", \"PAR 2\", \"PAR 3\", \"PAR 4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Dimmer $pixelKey\",\n            \"Strobe $pixelKey\"\n          ]\n        },\n        \"Flash 1 Strobe\",\n        \"Flash 2 Strobe\",\n        \"Flash 3 Strobe\",\n        \"Flash 4 Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showpro/litebar-h9.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Litebar H9\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"dywilson\", \"Flo Edelmann\"],\n    \"createDate\": \"2019-12-10\",\n    \"lastModifyDate\": \"2019-12-10\"\n  },\n  \"comment\": \"Seems to be manufactured by NiTEC but exclusively sold under the ShowPRO brand.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.showtech.com.au/webdata/LEDNIT150/downloads/LEDNIT150%20-%20Lite%20Bar%20Hex%209%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.showtech.com.au/product/litebar-h9/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=2tAa6qg27mw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1000, 56, 168],\n    \"weight\": 3.2,\n    \"power\": 77,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"9× 10W RGBAW+UV LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [29, 29]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [50, 50, 0],\n      \"spacing\": [61, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [9, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Segment 1\": [\"1\", \"2\", \"3\"],\n      \"Segment 2\": [\"4\", \"5\", \"6\"],\n      \"Segment 3\": [\"7\", \"8\", \"9\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Default dimmer speed set from menu\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed mode\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed mode 1\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed mode 2\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed mode 3\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Effects\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"0–100%\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"100–0%\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 114],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"comment\": \"100–0-100%\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [115, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [123, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 138],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [139, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 5\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [147, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 6\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [155, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 7\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [163, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 8\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 178],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 9\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [179, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 10\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [187, 194],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 11\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [195, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 12\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [203, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 13\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 218],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 14\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [219, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\",\n          \"comment\": \"cycles through programs 2-14\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [227, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"helpWanted\": \"Is this the correct direction?\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"UV $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"White Master\",\n        \"UV Master\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"White Master\",\n        \"UV Master\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Amber Master\",\n        \"White Master\",\n        \"UV Master\",\n        \"Color Macros\",\n        \"Strobe / Speed / Sound Sensitivity\",\n        \"Effects\",\n        \"Dimmer\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Segment 1\", \"Segment 2\", \"Segment 3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\",\n            \"UV $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"23-channel\",\n      \"shortName\": \"23ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"Segment 1\", \"Segment 2\", \"Segment 3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"Amber $pixelKey\",\n            \"White $pixelKey\",\n            \"UV $pixelKey\"\n          ]\n        },\n        \"Color Macros\",\n        \"Strobe / Speed / Sound Sensitivity\",\n        \"Effects\",\n        \"Dimmer\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/accent-spot-q4-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Accent Spot Q4 RGBW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2023-10-22\",\n    \"lastModifyDate\": \"2023-10-22\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/en/mwdownloads/download/link/id/17433647\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/42541-accent-spot-q4-rgbw.html\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 145\n  },\n  \"physical\": {\n    \"dimensions\": [160, 105, 245],\n    \"weight\": 1.7,\n    \"power\": 21,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 25W RGBW LED\",\n      \"lumens\": 572\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4.5, 4.5]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Linear Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"FX Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"CCT\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 24],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"1800K\"\n        },\n        {\n          \"dmxRange\": [25, 39],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2200K\"\n        },\n        {\n          \"dmxRange\": [40, 54],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [55, 69],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [85, 99],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [100, 114],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4500K\"\n        },\n        {\n          \"dmxRange\": [115, 129],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [145, 159],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [160, 174],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [175, 189],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7000K\"\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [205, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lexiconian Red\",\n          \"colors\": [\"#fe4548\"]\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lush Peach Sunsets\",\n          \"colors\": [\"#fe6e73\"]\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Neon Red\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff9600\"]\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Citrus Yellow\",\n          \"colors\": [\"#fcfe3a\"]\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fairy Green\",\n          \"colors\": [\"#77fe82\"]\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fake Ground Green\",\n          \"colors\": [\"#58fe5f\"]\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Viber Green\",\n          \"colors\": [\"#26fe2a\"]\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [84, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Neon Green\",\n          \"colors\": [\"#00ff32\"]\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Nightpaw\",\n          \"colors\": [\"#00ff96\"]\n        },\n        {\n          \"dmxRange\": [98, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [105, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Anime Sky Light Blue\",\n          \"colors\": [\"#35fcfe\"]\n        },\n        {\n          \"dmxRange\": [112, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Neon Poolside\",\n          \"colors\": [\"#56fbfe\"]\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Summer Azure\",\n          \"colors\": [\"#75acfe\"]\n        },\n        {\n          \"dmxRange\": [126, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Vibrant Sea Glass\",\n          \"colors\": [\"#4144fe\"]\n        },\n        {\n          \"dmxRange\": [133, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Excel Blue\",\n          \"colors\": [\"#2628fe\"]\n        },\n        {\n          \"dmxRange\": [140, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [147, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Perceptive Azure\",\n          \"colors\": [\"#4b00ff\"]\n        },\n        {\n          \"dmxRange\": [154, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#a000ff\"]\n        },\n        {\n          \"dmxRange\": [161, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [168, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta Rose\",\n          \"colors\": [\"#ff00af\"]\n        },\n        {\n          \"dmxRange\": [175, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fuchsia\",\n          \"colors\": [\"#ff0064\"]\n        },\n        {\n          \"dmxRange\": [182, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Flaming Melon\",\n          \"colors\": [\"#fe287f\"]\n        },\n        {\n          \"dmxRange\": [189, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rosanna Red\",\n          \"colors\": [\"#fe2840\"]\n        },\n        {\n          \"dmxRange\": [196, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Vogue Red\",\n          \"colors\": [\"#fe162f\"]\n        },\n        {\n          \"dmxRange\": [203, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chaos Red\",\n          \"colors\": [\"#ff0019\"]\n        },\n        {\n          \"dmxRange\": [210, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [217, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#f6fecb\"]\n        },\n        {\n          \"dmxRange\": [224, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#a8b0fe\"]\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW White\",\n          \"colors\": [\"#f4f9fe\"]\n        }\n      ]\n    },\n    \"Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [51, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Linear Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Linear Strobe\",\n        \"FX Strobe\",\n        \"CCT\",\n        \"Color Presets\",\n        \"Effect\",\n        \"Effect Speed\",\n        \"Sound Control\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/archi-painter-24-8-q4.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Archi Painter 24/8 Q4\",\n  \"shortName\": \"6ch\",\n  \"categories\": [\"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"1st truc\"],\n    \"createDate\": \"2019-05-17\",\n    \"lastModifyDate\": \"2019-05-17\"\n  },\n  \"comment\": \"Ordercode 40915\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/40915_MANUAL_GB_V1.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=VjIP45vs_mk\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [430, 425, 265],\n    \"weight\": 16,\n    \"power\": 140,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"24× 8W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fawn\",\n          \"colors\": [\"#e5aa70\"]\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#aa00ff\"]\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rosiness\",\n          \"colors\": [\"#ffbbdd\"]\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff00cc\"]\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tin Green\",\n          \"colors\": [\"#88bb88\"]\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Baby blue\",\n          \"colors\": [\"#66ccff\"]\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 1\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 2\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 3\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-Channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Functions\",\n        \"Program Speed\"\n      ]\n    },\n    {\n      \"name\": \"4-Channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-Channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Functions\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/atmos-2000.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Atmos 2000\",\n  \"shortName\": \"ShowtecAtm2000\",\n  \"categories\": [\"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-11-27\",\n    \"lastModifyDate\": \"2018-11-27\"\n  },\n  \"comment\": \"Ordercode 60873\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/60873_MANUAL_GB_V1.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=0WMvc7GCGFQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [320, 320, 500],\n    \"weight\": 7.04,\n    \"power\": 2000,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Fog\",\n        \"fogOutputStart\": \"0m^3/min\",\n        \"fogOutputEnd\": \"1133m^3/min\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Fog\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/club-par-12-4-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Club PAR 12/4 RGBW\",\n  \"shortName\": \"ClubPAR12-4rgbw\",\n  \"categories\": [\"Color Changer\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Voyo\"],\n    \"createDate\": \"2018-11-02\",\n    \"lastModifyDate\": \"2018-11-02\"\n  },\n  \"comment\": \"The Club Par 12-4 RGBW is an compact light effect with high output and great effects.\\nIdeal solution for small clubs and mobile DJs.\\nOrdercode: 42650\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/42650_MANUAL_GB_V1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/42650-club-par-12-4-rgbw.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=9CTsLX5hNuU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [288, 170, 113],\n    \"weight\": 2.2,\n    \"power\": 77,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 8W RGBW LEDs\",\n      \"lumens\": 3200\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [13, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Built in programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Fade Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"instant\",\n        \"timeEnd\": \"long\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGBW\",\n      \"shortName\": \"rgbw\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"DRGBW Strobe & Program\",\n      \"shortName\": \"drgbw-strb-prg\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Built in programs\",\n        \"Program Speed\",\n        \"Fade Time\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/club-par-12-6-rgbwauv.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Club Par 12/6 RGBWAUV\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Tobias\"],\n    \"createDate\": \"2022-11-03\",\n    \"lastModifyDate\": \"2022-11-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/en/mwdownloads/download/link/id/17430150/\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/42651-club-par-12-6-rgbwauv.html\"\n    ],\n    \"video\": [\n      \"https://vimeo.com/129770259\"\n    ]\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"helpWanted\": \"The manual says “Closed” here, but then strobe could never be disabled. Is the light constantly on or off at DMX values 0…12 and at DMX value 255?\"\n        },\n        {\n          \"dmxRange\": [13, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\"\n        },\n        {\n          \"dmxRange\": [140, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Program Duration\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"instant\",\n        \"durationEnd\": \"long\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Amber\",\n        \"White\",\n        \"UV\",\n        \"Strobe\",\n        \"Program\",\n        \"Program Speed\",\n        \"Program Duration\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/compact-par-18.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Compact Par 18\",\n  \"shortName\": \"ShowtecCompactPar18\",\n  \"categories\": [\"Dimmer\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"aHa Friedberg\"],\n    \"createDate\": \"2019-08-26\",\n    \"lastModifyDate\": \"2019-08-26\"\n  },\n  \"comment\": \"Ordercode 42592\",\n  \"links\": {\n    \"manual\": [\n      \"https://assets.highlite.com/attachments/MANUAL/42592_MANUAL_GB_V1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/42592-compact-par-18-mkii.html\"\n    ],\n    \"video\": [\n      \"https://vimeo.com/202769399\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [250, 290, 96],\n    \"weight\": 2.84,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"18× 3W RGB LEDs\",\n      \"lumens\": 9600\n    },\n    \"lens\": {\n      \"degreesMinMax\": [28, 28]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"RGB Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 1\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 2\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 3\",\n          \"colors\": [\"#ff9600\"]\n        },\n        {\n          \"dmxRange\": [27, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 4\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [36, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 5\",\n          \"colors\": [\"#c8ff00\"]\n        },\n        {\n          \"dmxRange\": [45, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 6\",\n          \"colors\": [\"#64ff00\"]\n        },\n        {\n          \"dmxRange\": [54, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 7\",\n          \"colors\": [\"#28ff00\"]\n        },\n        {\n          \"dmxRange\": [63, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 8\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [72, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 9\",\n          \"colors\": [\"#00ff32\"]\n        },\n        {\n          \"dmxRange\": [81, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 10\",\n          \"colors\": [\"#00ff96\"]\n        },\n        {\n          \"dmxRange\": [90, 98],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 11\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [99, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 12\",\n          \"colors\": [\"#0096ff\"]\n        },\n        {\n          \"dmxRange\": [108, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 13\",\n          \"colors\": [\"#0032ff\"]\n        },\n        {\n          \"dmxRange\": [117, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 14\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [126, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 15\",\n          \"colors\": [\"#3200ff\"]\n        },\n        {\n          \"dmxRange\": [135, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 16\",\n          \"colors\": [\"#9600fa\"]\n        },\n        {\n          \"dmxRange\": [144, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 17\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [153, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 18\",\n          \"colors\": [\"#dc0032\"]\n        },\n        {\n          \"dmxRange\": [162, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 19\",\n          \"colors\": [\"#963264\"]\n        },\n        {\n          \"dmxRange\": [171, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 20\",\n          \"colors\": [\"#32b4dc\"]\n        },\n        {\n          \"dmxRange\": [180, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 21\",\n          \"colors\": [\"#32dc64\"]\n        },\n        {\n          \"dmxRange\": [189, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 22\",\n          \"colors\": [\"#96dc00\"]\n        },\n        {\n          \"dmxRange\": [198, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 23\",\n          \"colors\": [\"#9600dc\"]\n        },\n        {\n          \"dmxRange\": [207, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 24\",\n          \"colors\": [\"#00b4dc\"]\n        },\n        {\n          \"dmxRange\": [216, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 25\",\n          \"colors\": [\"#00dc32\"]\n        },\n        {\n          \"dmxRange\": [225, 233],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 26\",\n          \"colors\": [\"#dc6432\"]\n        },\n        {\n          \"dmxRange\": [234, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 27\",\n          \"colors\": [\"#dcc864\"]\n        },\n        {\n          \"dmxRange\": [243, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 28\",\n          \"colors\": [\"#ffc896\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 29\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Macros\": {\n      \"highlightValue\": 252,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [23, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [46, 68],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [69, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [92, 114],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [115, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [138, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ddaaff\"]\n        },\n        {\n          \"dmxRange\": [161, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [184, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dark blue\",\n          \"colors\": [\"#0000aa\"]\n        },\n        {\n          \"dmxRange\": [207, 229],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light green\",\n          \"colors\": [\"#aaffaa\"]\n        },\n        {\n          \"dmxRange\": [230, 252],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [253, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm white\",\n          \"colors\": [\"#ffeebb\"]\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"29 static colors\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"RGB Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7-color\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3-color\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7-color\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3-color\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fantasy change 1\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fantasy change 2\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red gradual change\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Green gradual change\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blue gradual change\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1Channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"3Channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4Channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"6Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red / RGB Macros / Program Speed / Sound Sensitivity\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Color Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/compact-par-7-tri.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Compact Par 7 Tri\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"sonotron\", \"Felix Edelmann\"],\n    \"createDate\": \"2020-02-19\",\n    \"lastModifyDate\": \"2020-02-19\"\n  },\n  \"comment\": \"Ordercode 42580\",\n  \"links\": {\n    \"manual\": [\n      \"https://assets.highlite.com/attachments/MANUAL/42580_MANUAL_GB_V2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/42580-compact-par-7-tri.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Zu3i_x9KKoU\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [275, 256, 95],\n    \"weight\": 2.2,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7× RGB LEDs\",\n      \"lumens\": 1540\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"RGB Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 1\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 2\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 3\",\n          \"colors\": [\"#ff9600\"]\n        },\n        {\n          \"dmxRange\": [27, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 4\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [36, 44],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 5\",\n          \"colors\": [\"#c8ff00\"]\n        },\n        {\n          \"dmxRange\": [45, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 6\",\n          \"colors\": [\"#64ff00\"]\n        },\n        {\n          \"dmxRange\": [54, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 7\",\n          \"colors\": [\"#28ff00\"]\n        },\n        {\n          \"dmxRange\": [63, 71],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 8\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [72, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 9\",\n          \"colors\": [\"#00ff32\"]\n        },\n        {\n          \"dmxRange\": [81, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 10\",\n          \"colors\": [\"#00ff96\"]\n        },\n        {\n          \"dmxRange\": [90, 98],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 11\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [99, 107],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 12\",\n          \"colors\": [\"#0096ff\"]\n        },\n        {\n          \"dmxRange\": [108, 116],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 13\",\n          \"colors\": [\"#0032ff\"]\n        },\n        {\n          \"dmxRange\": [117, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 14\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [126, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 15\",\n          \"colors\": [\"#3200ff\"]\n        },\n        {\n          \"dmxRange\": [135, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 16\",\n          \"colors\": [\"#9600fa\"]\n        },\n        {\n          \"dmxRange\": [144, 152],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 17\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [153, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 18\",\n          \"colors\": [\"#dc0032\"]\n        },\n        {\n          \"dmxRange\": [162, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 19\",\n          \"colors\": [\"#963264\"]\n        },\n        {\n          \"dmxRange\": [171, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 20\",\n          \"colors\": [\"#32b4dc\"]\n        },\n        {\n          \"dmxRange\": [180, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 21\",\n          \"colors\": [\"#32dc64\"]\n        },\n        {\n          \"dmxRange\": [189, 197],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 22\",\n          \"colors\": [\"#96dc00\"]\n        },\n        {\n          \"dmxRange\": [198, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 23\",\n          \"colors\": [\"#9600dc\"]\n        },\n        {\n          \"dmxRange\": [207, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 24\",\n          \"colors\": [\"#00b4dc\"]\n        },\n        {\n          \"dmxRange\": [216, 224],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 25\",\n          \"colors\": [\"#00dc32\"]\n        },\n        {\n          \"dmxRange\": [225, 233],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 26\",\n          \"colors\": [\"#dc6432\"]\n        },\n        {\n          \"dmxRange\": [234, 242],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 27\",\n          \"colors\": [\"#dcc864\"]\n        },\n        {\n          \"dmxRange\": [243, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 28\",\n          \"colors\": [\"#ffc896\"]\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGB macro 29\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"29 static colors\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"RGB Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7-color\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3-color\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7-color\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3-color\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fantasy change 1\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fantasy change 2\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red gradual change\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Green gradual change\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blue gradual change\",\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Red / RGB Macros / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"ID Address\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 1-66\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 13\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 14\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 15\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 16\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 17\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 18\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 19\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 20\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 21\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 22\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 23\"\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 24\"\n        },\n        {\n          \"dmxRange\": [214, 214],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 25\"\n        },\n        {\n          \"dmxRange\": [215, 215],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 26\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 27\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 28\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 29\"\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 30\"\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 31\"\n        },\n        {\n          \"dmxRange\": [221, 221],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 32\"\n        },\n        {\n          \"dmxRange\": [222, 222],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 33\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 34\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 35\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 36\"\n        },\n        {\n          \"dmxRange\": [226, 226],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 37\"\n        },\n        {\n          \"dmxRange\": [227, 227],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 38\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 39\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 40\"\n        },\n        {\n          \"dmxRange\": [230, 230],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 41\"\n        },\n        {\n          \"dmxRange\": [231, 231],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 42\"\n        },\n        {\n          \"dmxRange\": [232, 232],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 43\"\n        },\n        {\n          \"dmxRange\": [233, 233],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 44\"\n        },\n        {\n          \"dmxRange\": [234, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 45\"\n        },\n        {\n          \"dmxRange\": [235, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 46\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 47\"\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 48\"\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 49\"\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 50\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 51\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 52\"\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 53\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 54\"\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 55\"\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 56\"\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 57\"\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 58\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 59\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 60\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 61\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 62\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 63\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 64\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 65\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 66\"\n        }\n      ]\n    },\n    \"Fader Response\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 250],\n          \"type\": \"Time\",\n          \"time\": \"instant\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Time\",\n          \"time\": \"long\",\n          \"comment\": \"delayed response\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red / RGB Macros / Program Speed / Sound Sensitivity\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Color Programs\",\n        \"ID Address\",\n        \"Fader Response\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/dim-4lc.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"DIM-4LC\",\n  \"comment\": \"4-Channel Dimmer Pack with local control - 3 A per channel\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Paul Rogalski\"],\n    \"createDate\": \"2024-10-02\",\n    \"lastModifyDate\": \"2024-10-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/en/mwdownloads/download/link/id/17431130\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/products/entertainment-lighting/light-controllers/50443-dim-4lc.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [275, 220, 82],\n    \"weight\": 3.5,\n    \"power\": 3000,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": [\"1\", \"2\"],\n      \"3/4\": [\"3\", \"4\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"off\",\n        \"brightnessEnd\": \"bright\"\n      }\n    },\n    \"Switch $pixelKey\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Intensity\",\n          \"brightness\": \"bright\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel Dimmer\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer Master\"\n      ]\n    },\n    {\n      \"name\": \"1-channel Switch\",\n      \"shortName\": \"1ch-switch\",\n      \"channels\": [\n        \"Switch Master\"\n      ]\n    },\n    {\n      \"name\": \"2-channel Dimmer\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer 1/2\",\n        \"Dimmer 3/4\"\n      ]\n    },\n    {\n      \"name\": \"2-channel Switch\",\n      \"shortName\": \"2ch-switch\",\n      \"channels\": [\n        \"Switch 1/2\",\n        \"Switch 3/4\"\n      ]\n    },\n    {\n      \"name\": \"4-channel Dimmer\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer 1\",\n        \"Dimmer 2\",\n        \"Dimmer 3\",\n        \"Dimmer 4\"\n      ]\n    },\n    {\n      \"name\": \"4-channel Switch\",\n      \"shortName\": \"4ch-switch\",\n      \"channels\": [\n        \"Switch 1\",\n        \"Switch 2\",\n        \"Switch 3\",\n        \"Switch 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/dominator.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Dominator\",\n  \"shortName\": \"ShowtecDominator\",\n  \"categories\": [\"Laser\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2017-11-17\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"comment\": \"Version 1 and 2's DMX protocols are identical, only their physical data differs\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/43153_MANUAL_GB_V2.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=gYOyC0gVZfI\",\n      \"https://www.youtube.com/watch?v=9k_C40lfF5s\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [298, 310, 225],\n    \"weight\": 4.06,\n    \"power\": 66,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"5x3W LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Programs\": {\n      \"defaultValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 1 (Strobe, Derby, Laser)\"\n        },\n        {\n          \"dmxRange\": [25, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 2 (Derby, Laser)\"\n        },\n        {\n          \"dmxRange\": [40, 54],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 3 (Strobe, Laser)\"\n        },\n        {\n          \"dmxRange\": [55, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 4 (Derby, Laser)\"\n        },\n        {\n          \"dmxRange\": [70, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 5 (Derby)\"\n        },\n        {\n          \"dmxRange\": [85, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 6 (Laser)\"\n        },\n        {\n          \"dmxRange\": [100, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 7 (Strobe)\"\n        },\n        {\n          \"dmxRange\": [115, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 1 (Strobe, Derby, Laser)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [130, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 2 (Derby, Laser)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [145, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 3 (Strobe, Laser)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [160, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 4 (Derby, Laser)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [175, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 5 (Derby)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [190, 204],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 6 (Laser)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [205, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound 7 (Strobe)\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"NoFunction\",\n          \"comment\": \"DMX mode\"\n        }\n      ]\n    },\n    \"Derby Colors\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#ff0000\"],\n          \"comment\": \"White + Red\"\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Amber + White\"\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#00ff00\"],\n          \"comment\": \"White + Green\"\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ffbf00\"],\n          \"comment\": \"Green + Amber\"\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ff0000\"],\n          \"comment\": \"Amber + Red\"\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [90, 94],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffbf00\"],\n          \"comment\": \"Red + Green + Amber\"\n        },\n        {\n          \"dmxRange\": [95, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Red + Green + White\"\n        },\n        {\n          \"dmxRange\": [100, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffbf00\", \"#0000ff\"],\n          \"comment\": \"Red + Amber + Blue\"\n        },\n        {\n          \"dmxRange\": [105, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Blue + White\"\n        },\n        {\n          \"dmxRange\": [110, 114],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffbf00\", \"#ffffff\"],\n          \"comment\": \"Red + Amber + White\"\n        },\n        {\n          \"dmxRange\": [115, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Amber + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [120, 124],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [125, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Amber + Green + White\"\n        },\n        {\n          \"dmxRange\": [130, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\", \"#ffffff\", \"#0000ff\"],\n          \"comment\": \"Amber + White + Blue\"\n        },\n        {\n          \"dmxRange\": [135, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"Red + Green + Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [140, 144],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [145, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\", \"#ffffff\", \"#ffbf00\"],\n          \"comment\": \"Green + Blue + White + Amber\"\n        },\n        {\n          \"dmxRange\": [150, 154],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#ffffff\", \"#ffbf00\"],\n          \"comment\": \"Red + Green + White + Amber\"\n        },\n        {\n          \"dmxRange\": [155, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#ffffff\", \"#ffbf00\"],\n          \"comment\": \"Red + Blue + White + Amber\"\n        },\n        {\n          \"dmxRange\": [160, 164],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\", \"#ffbf00\"],\n          \"comment\": \"Red + Green + Blue + White + Amber\"\n        },\n        {\n          \"dmxRange\": [165, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic (single color)\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic (two colors)\"\n        }\n      ]\n    },\n    \"Derby Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"LED Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [7, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"30Hz\",\n          \"speedEnd\": \"0Hz\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"LED Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [110, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Full on\"\n        }\n      ]\n    },\n    \"Laser\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [10, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red laser\"\n        },\n        {\n          \"dmxRange\": [50, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green laser\"\n        },\n        {\n          \"dmxRange\": [90, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green alternating\"\n        },\n        {\n          \"dmxRange\": [130, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green Strobe\"\n        },\n        {\n          \"dmxRange\": [170, 209],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red Strobe + Green\"\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red Strobe + Green Strobe\"\n        }\n      ]\n    },\n    \"Laser Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"helpWanted\": \"Is this really a blackout, or rather a 'No strobe' capability?\"\n        },\n        {\n          \"dmxRange\": [5, 254],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Rotating Derby\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [5, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Rotating Laser\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [5, 127],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [128, 133],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel Version 1\",\n      \"shortName\": \"9ch-V1\",\n      \"channels\": [\n        \"Programs\",\n        \"Derby Colors\",\n        \"Derby Speed\",\n        \"LED Strobe\",\n        \"LED Programs\",\n        \"Laser\",\n        \"Laser Strobe\",\n        \"Rotating Derby\",\n        \"Rotating Laser\"\n      ]\n    },\n    {\n      \"name\": \"9-channel Version 2\",\n      \"shortName\": \"9ch-V2\",\n      \"physical\": {\n        \"dimensions\": [307, 312, 200],\n        \"weight\": 3.92,\n        \"bulb\": {\n          \"type\": \"8x3W LEDs\"\n        }\n      },\n      \"channels\": [\n        \"Programs\",\n        \"Derby Colors\",\n        \"Derby Speed\",\n        \"LED Strobe\",\n        \"LED Programs\",\n        \"Laser\",\n        \"Laser Strobe\",\n        \"Rotating Derby\",\n        \"Rotating Laser\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/explorer-250-wash-pro.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Explorer 250 Wash\",\n  \"categories\": [\"Color Changer\", \"Moving Head\"],\n  \"meta\": {\n    \"authors\": [\"Luke Nelson\"],\n    \"createDate\": \"2023-10-15\",\n    \"lastModifyDate\": \"2023-10-15\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2023-05-06\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.6)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/837961/Showtec-Explorer-250-Wash.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_E7AQH2ugoM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [379, 476, 428],\n    \"weight\": 33.5,\n    \"power\": 350,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"MSD 250\",\n      \"lumens\": 6700\n    },\n    \"lens\": {\n      \"name\": \"Fresnel\",\n      \"degreesMinMax\": [8, 22]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTF 3200K\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTF 5300K\",\n          \"colorTemperature\": \"5300K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#8000ff\"]\n        }\n      ]\n    },\n    \"Effect Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Frost\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Beam shaper\"\n        }\n      ]\n    },\n    \"CMY Color effect-wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        },\n        {\n          \"type\": \"Color\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan Fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"530deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt Fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"280deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Lamp On, Off & Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 139],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Lamp on / reset\"\n        },\n        {\n          \"dmxRange\": [140, 229],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Lamp off\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [18, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [36, 53],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [54, 72],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [73, 90],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [91, 108],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [109, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [128, 190],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [191, 192],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Cyan\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cyan\"\n      }\n    },\n    \"Magenta\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Magenta\"\n      }\n    },\n    \"Yellow\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Yellow\"\n      }\n    },\n    \"CMY speed adjust\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Effect Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [71, 180],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [181, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"slotNumber\": 3,\n          \"angleStart\": \"0%\",\n          \"angleEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Keep\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Maintenance\",\n        \"comment\": \"Keep this Color setting\",\n        \"helpWanted\": \"What does this do?\"\n      }\n    },\n    \"CMY Color effect-wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 19\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 20\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 21\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 22\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 23\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 24\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 25\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 26\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 27\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 28\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 29\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 30\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 31\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 32\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan Fine\",\n        \"Tilt Fine\",\n        \"Pan/Tilt Speed\",\n        \"Lamp On, Off & Reset\",\n        \"Color Wheel\",\n        \"Cyan\",\n        \"Magenta\",\n        \"Yellow\",\n        \"CMY speed adjust\",\n        \"CMY Color effect-wheel\",\n        \"Effect Wheel\",\n        \"Keep\",\n        \"Shutter / Strobe\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/horizon-8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Horizon 8\",\n  \"shortName\": \"Hrzn8\",\n  \"categories\": [\"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-07-08\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"comment\": \"Beam Angle: 45x60°\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/43536_MANUAL_GB_V1.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [622, 299, 310],\n    \"weight\": 15,\n    \"power\": 298,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 7200\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1\", \"2\", \"3\", \"4\"],\n        [\"5\", \"6\", \"7\", \"8\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"P1\": [\"1\", \"2\", \"3\", \"4\"],\n      \"P2\": [\"5\", \"6\", \"7\", \"8\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"fineChannelAliases\": [\"Amber fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Macro Colors\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"],\n          \"comment\": \"Red 100% / Green Up / Blue 0%\"\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"Red Down / Green 100% / Blue 0%\"\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"],\n          \"comment\": \"Red 0% / Green 100% / Blue Up\"\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Red 0% / Green Down / Blue 100%\"\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"],\n          \"comment\": \"Red Up / Green 0% / Blue 100%\"\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"],\n          \"comment\": \"Red 100% / Green 0% / Blue Down\"\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"],\n          \"comment\": \"Red 100% / Green Up / Blue Up\"\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Red Down / Green Down / Blue 100%\"\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffeaaa\"],\n          \"comment\": \"Red 100% / Green 100% / Blue 100% / White 100% / Amber 100%\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffb87b\"],\n          \"colorTemperature\": \"3200K\",\n          \"comment\": \"White 1\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbe87\"],\n          \"colorTemperature\": \"3400K\",\n          \"comment\": \"White 2\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd3af\"],\n          \"colorTemperature\": \"4200K\",\n          \"comment\": \"White 3\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffe2ca\"],\n          \"colorTemperature\": \"4900K\",\n          \"comment\": \"White 4\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffefe1\"],\n          \"colorTemperature\": \"5600K\",\n          \"comment\": \"White 5\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fff4ea\"],\n          \"colorTemperature\": \"5900K\",\n          \"comment\": \"White 6\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fffefa\"],\n          \"colorTemperature\": \"6500K\",\n          \"comment\": \"White 7\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#edefff\"],\n          \"colorTemperature\": \"7200K\",\n          \"comment\": \"White 8\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dde6ff\"],\n          \"colorTemperature\": \"8000K\",\n          \"comment\": \"White 9\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#d7e2ff\"],\n          \"colorTemperature\": \"8500K\",\n          \"comment\": \"White 10\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#cadaff\"],\n          \"colorTemperature\": \"10000K\",\n          \"comment\": \"White 11\"\n        }\n      ]\n    },\n    \"Clas Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 0\",\n          \"helpWanted\": \"Can we make these Clas Strobe capabilities more informative?\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 13\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 14\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 15\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 16\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 17\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 18\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 19\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Clas Strobe 20\"\n        }\n      ]\n    },\n    \"Spec Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [110, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Lightning\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Auto/Custom Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 40],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 1\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 2\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 3\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 4\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 5\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 6\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 7\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 8\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 9\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto 10\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Red\",\n            \"Green / Fade Time\": \"Green\",\n            \"Dimmer fine / Step Time\": \"Dimmer fine\",\n            \"Red / Fade Time\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 1\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 2\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 3\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 4\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 5\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 6\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 7\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 8\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [221, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 9\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Custom 10\",\n          \"switchChannels\": {\n            \"Red / Step Time\": \"Step Time\",\n            \"Green / Fade Time\": \"Fade Time\",\n            \"Dimmer fine / Step Time\": \"Step Time\",\n            \"Red / Fade Time\": \"Fade Time\"\n          }\n        }\n      ]\n    },\n    \"Auto Speed Adjustment\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Return settings\"\n        },\n        {\n          \"dmxRange\": [10, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear dimmer\"\n        },\n        {\n          \"dmxRange\": [30, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [70, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"66%\"\n        },\n        {\n          \"dmxRange\": [130, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"33%\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Non-linear dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"helpWanted\": \"Which DMX values correspond to which color?\"\n      }\n    },\n    \"Saturation\": {\n      \"capability\": {\n        \"type\": \"Generic\"\n      }\n    },\n    \"Value\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Step Time\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"short\",\n        \"durationEnd\": \"long\"\n      }\n    },\n    \"Fade Time\": {\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"short\",\n        \"durationEnd\": \"long\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"$pixelKey Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Tour (Clas Strobe)\",\n      \"shortName\": \"Tour-Clas\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red / Step Time\",\n        \"Green / Fade Time\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Macro Colors\",\n        \"Clas Strobe\",\n        \"Auto/Custom Programs\",\n        \"Auto Speed Adjustment\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"Tour (Spec Strobe)\",\n      \"shortName\": \"Tour-Spec\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red / Step Time\",\n        \"Green / Fade Time\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Macro Colors\",\n        \"Spec Strobe\",\n        \"Auto/Custom Programs\",\n        \"Auto Speed Adjustment\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"Tour 16-bit (Clas Strobe)\",\n      \"shortName\": \"TR16-Clas\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine / Step Time\",\n        \"Red / Fade Time\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Amber\",\n        \"Amber fine\",\n        \"Macro Colors\",\n        \"Clas Strobe\",\n        \"Auto/Custom Programs\",\n        \"Auto Speed Adjustment\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"Tour 16-bit (Spec Strobe)\",\n      \"shortName\": \"TR16-Spec\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Dimmer fine / Step Time\",\n        \"Red / Fade Time\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Amber\",\n        \"Amber fine\",\n        \"Macro Colors\",\n        \"Spec Strobe\",\n        \"Auto/Custom Programs\",\n        \"Auto Speed Adjustment\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"ARC1\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"AR1.D\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"ARC2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"ARC3\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"AR3.D\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"AR3.S (Clas Strobe)\",\n      \"shortName\": \"AR3.S-Clas\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Clas Strobe\"\n      ]\n    },\n    {\n      \"name\": \"AR3.S (Spec Strobe)\",\n      \"shortName\": \"AR3.S-Spec\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Spec Strobe\"\n      ]\n    },\n    {\n      \"name\": \"HSV\",\n      \"channels\": [\n        \"Hue\",\n        \"Saturation\",\n        \"Value\"\n      ]\n    },\n    {\n      \"name\": \"PIX1\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelGroup\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"PIX3\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelGroup\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\",\n            \"$pixelKey Amber\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/kanjo-spot-60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Kanjo Spot 60\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2017-09-09\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/45011_MANUAL_GB_V2.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Tpf2d5KYidA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [167, 270, 145],\n    \"weight\": 2.9,\n    \"power\": 85,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"60W White LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [18, 18]\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Pan / Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bd1007\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff01\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0d3fd6\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fefe01\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dd127b\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0099ff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff6600\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe / Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\",\n          \"randomTiming\": true\n        }\n      ]\n    },\n    \"Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 93],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [94, 94],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset settings\"\n        },\n        {\n          \"dmxRange\": [95, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Restore factory settings\"\n        },\n        {\n          \"dmxRange\": [96, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Mode\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan / Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Strobe / Shutter\",\n        \"Functions\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan / Tilt Speed\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Dimmer\",\n        \"Strobe / Shutter\",\n        \"Functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/kanjo-wash-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Kanjo Wash RGB\",\n  \"shortName\": \"KanjoWash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-01-20\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/45000_MANUAL_GB_V1.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=rjNdcv8ciAI\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [169, 270, 156],\n    \"weight\": 2.52,\n    \"power\": 43,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [14, 26],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#aa00ff\"],\n          \"comment\": \"Purple\"\n        },\n        {\n          \"dmxRange\": [27, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ea\"],\n          \"comment\": \"Purple / Red\"\n        },\n        {\n          \"dmxRange\": [40, 52],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaa00\"],\n          \"comment\": \"Orange\"\n        },\n        {\n          \"dmxRange\": [53, 65],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [66, 78],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffaaff\"],\n          \"comment\": \"Bright Pink\"\n        },\n        {\n          \"dmxRange\": [79, 91],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#55ff7f\"],\n          \"comment\": \"Bright green\"\n        },\n        {\n          \"dmxRange\": [92, 104],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00aaff\"],\n          \"comment\": \"Bright blue\"\n        },\n        {\n          \"dmxRange\": [105, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [118, 130],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fff9e0\"],\n          \"comment\": \"Warm White\",\n          \"colorTemperature\": \"warm\"\n        },\n        {\n          \"dmxRange\": [131, 143],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [144, 156],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [157, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [170, 182],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [183, 195],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [196, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7 colors\"\n        },\n        {\n          \"dmxRange\": [224, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change\",\n          \"helpWanted\": \"How does Color Change differ from Jump or Fade (Gradient)?\",\n          \"comment\": \"7 colors\"\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 colors\"\n        }\n      ]\n    },\n    \"Color Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [3, 101],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1 (fast)\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2 (gradient and jump)\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3 (slow)\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4 (sound-controlled)\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Factory reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset to factory settings\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Pan/Tilt Speed\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Presets\",\n        \"Color Speed\",\n        \"Programs\",\n        \"Factory reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/led-blinder-2-cob.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Blinder 2 COB\",\n  \"categories\": [\"Blinder\", \"Dimmer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Eric Bessot\", \"Luke Nelson\"],\n    \"createDate\": \"2023-05-07\",\n    \"lastModifyDate\": \"2023-05-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.woodbrass.com/images/woodbrass/SHOWTEC+LED+BLINDER+2+50W.PDF\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [138, 393, 185],\n    \"weight\": 4.14,\n    \"power\": 110,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 3200\n    },\n    \"lens\": {\n      \"degreesMinMax\": [35, 35]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [[\"L\", \"R\"]]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"StrobeSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer Master\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer L\",\n        \"Dimmer R\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer L\",\n        \"Dimmer R\",\n        \"Dimmer Master\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer L\",\n        \"Dimmer R\",\n        \"Strobe\",\n        \"Dimmer Master\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/led-light-bar-rgb-v3.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Light Bar RGB V3\",\n  \"shortName\": \"LEDLightBar\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-01-20\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"comment\": \"Ordercode 42202\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/42202_MANUAL_GB_V3.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1070, 65, 88],\n    \"weight\": 1.68,\n    \"power\": 70,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"name\": \"Other\",\n      \"degreesMinMax\": [40, 40]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [250, 60, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1/4\", \"2/4\", \"3/4\", \"4/4\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"1/2\": [\"1/4\", \"2/4\"],\n      \"2/2\": [\"3/4\", \"4/4\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe1\": {\n      \"name\": \"Strobe\",\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"20Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Strobe2\": {\n      \"name\": \"Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Purple\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\",\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Mic Sensitivity\": \"Mic Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mic Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Operation Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Effect\",\n          \"effectName\": \"RGB Mode\"\n        },\n        {\n          \"dmxRange\": [10, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"P1 (3 channels)\",\n      \"shortName\": \"P1\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"P2 (4 channels)\",\n      \"shortName\": \"P2\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"P3 (8 channels)\",\n      \"shortName\": \"P3\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe1\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"P4 (14 channels)\",\n      \"shortName\": \"P4\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe1\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"P5 (2 channels)\",\n      \"shortName\": \"P5\",\n      \"channels\": [\n        \"Color Programs\",\n        \"Program Speed / Mic Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"P6 (15 channels)\",\n      \"shortName\": \"P6\",\n      \"channels\": [\n        \"Operation Mode\",\n        \"Dimmer\",\n        \"Strobe2\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"P7 (7 channels)\",\n      \"shortName\": \"P7\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Programs\",\n        \"Program Speed / Mic Sensitivity\",\n        \"Strobe1\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/performer-2500.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Performer 2500\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"purple\", \"Luke Nelson\"],\n    \"createDate\": \"2022-10-19\",\n    \"lastModifyDate\": \"2022-10-19\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.highlite.com/en/33141-performer-2500-fresnel.html\"\n    ],\n    \"manual\": [\n      \"https://www.highlite.com/en/mwdownloads/download/link/id/17429015/\"\n    ],\n    \"video\": [\n      \"https://vimeo.com/439925462\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [450, 380, 470],\n    \"weight\": 10,\n    \"power\": 265,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 6959\n    },\n    \"lens\": {\n      \"name\": \"Fresnel\",\n      \"degreesMinMax\": [10, 60]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"fineChannelAliases\": [\"Master Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Warm White\": {\n      \"fineChannelAliases\": [\"Warm White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"Natural White\": {\n      \"fineChannelAliases\": [\"Natural White fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"CCT\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 35],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2700K\"\n        },\n        {\n          \"dmxRange\": [36, 60],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"dmxRange\": [61, 85],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [86, 110],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [111, 135],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3600K\"\n        },\n        {\n          \"dmxRange\": [136, 160],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3800K\"\n        },\n        {\n          \"dmxRange\": [161, 185],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [186, 210],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [211, 235],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4500K\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [110, 179],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Lightning\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"25Hz\",\n          \"randomTiming\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"UNO\",\n      \"channels\": [\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"DOS\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"VW.D\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Warm White\",\n        \"Natural White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"VW.F\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Warm White\",\n        \"Warm White fine\",\n        \"Natural White\",\n        \"Natural White fine\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"STD.P\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Master Dimmer fine\",\n        \"Warm White\",\n        \"Warm White fine\",\n        \"Natural White\",\n        \"Natural White fine\",\n        \"CCT\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/phantom-140-led-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Phantom 140 LED Beam\",\n  \"shortName\": \"Phant140\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\", \"Felix Edelmann\"],\n    \"createDate\": \"2017-05-24\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"comment\": \"Ordercode 40194\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/40194_MANUAL_GB_V2.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=wJxhroCbM5U\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [330, 460, 245],\n    \"weight\": 17.28,\n    \"power\": 230,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 4]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#fffc00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Pink\",\n          \"colors\": [\"#ff8697\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#1c7403\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#cd000f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Bright Blue\",\n          \"colors\": [\"#0065fd\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#60fb0a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Yellow\",\n          \"colors\": [\"#e1e900\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Old Yellow\",\n          \"colors\": [\"#ff9c03\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Violet\",\n          \"colors\": [\"#7173c8\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Hard Pink\",\n          \"colors\": [\"#ee008a\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#6ea4ee\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Moon Yellow\",\n          \"colors\": [\"#f8d158\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Steel Blue\",\n          \"colors\": [\"#d6e5fc\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#33199e\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10.5\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11.5\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12.5\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13.5\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14.5\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15.5\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"defaultValue\": 255,\n      \"highlightValue\": 200,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 76],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [77, 145],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [146, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"randomTiming\": true,\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [72, 77],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 18,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [78, 83],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 17,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [84, 89],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 16,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [90, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 101],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [102, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [108, 113],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [114, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 125],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 131],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 137],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [138, 143],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [150, 155],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [156, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [162, 167],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [168, 173],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [174, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [180, 217],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [218, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Pan/Tilt\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Colorwheel\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Gobowheel\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Pan/Tilt/Colorwheel\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Pan/Tilt/Gobowheel\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Pan/Tilt/Gobowheel/Colorwheel\"\n        },\n        {\n          \"dmxRange\": [56, 95],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Tilt\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Colorwheel\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Gobowheel\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Prism\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Focus\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all Channels\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 8\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Prism\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 12],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet\"\n        },\n        {\n          \"dmxRange\": [13, 130],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [131, 247],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"8-facet\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Gobo Wheel\",\n        \"Functions\",\n        \"Programs\",\n        \"Prism\",\n        \"Focus\",\n        \"Frost\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Shutter\",\n        \"Gobo Wheel\",\n        \"Prism\",\n        \"Focus\",\n        \"Frost\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/phantom-25-led-wash.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Phantom 25 LED Wash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\"],\n    \"createDate\": \"2021-09-14\",\n    \"lastModifyDate\": \"2021-09-14\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://gzhls.at/blob/ldb/5/5/2/1/3a93c224615375e06615bb662d13378e9580.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.musikhaus-korn.de/de/showtec-phantom-25-led-wash-moving-head/pd/47262\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=3j6SDpwsrEM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [205, 230, 210],\n    \"weight\": 3.7,\n    \"power\": 105,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"25W White LED\",\n      \"lumens\": 543\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 132],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [133, 134],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [135, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"LED Color Saturation\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"dark\",\n        \"brightnessEnd\": \"bright\"\n      }\n    },\n    \"Macro\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 21],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW full on\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [22, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [36, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [50, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [64, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [78, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 1\"\n        },\n        {\n          \"dmxRange\": [92, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 2\"\n        },\n        {\n          \"dmxRange\": [106, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 3\"\n        },\n        {\n          \"dmxRange\": [120, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 4\"\n        },\n        {\n          \"dmxRange\": [134, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 5\"\n        },\n        {\n          \"dmxRange\": [148, 161],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 6\"\n        },\n        {\n          \"dmxRange\": [162, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 7\"\n        },\n        {\n          \"dmxRange\": [176, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 8\"\n        },\n        {\n          \"dmxRange\": [190, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 9\"\n        },\n        {\n          \"dmxRange\": [204, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 10\"\n        },\n        {\n          \"dmxRange\": [218, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Macro 11\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Rainbow\"\n        }\n      ]\n    },\n    \"LED Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Channel Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 27],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [28, 147],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable blackout during Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [148, 167],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan\"\n        },\n        {\n          \"dmxRange\": [168, 187],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Tilt\"\n        },\n        {\n          \"dmxRange\": [188, 227],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [228, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all channels\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Shutter / Strobe\",\n        \"White\",\n        \"Macro\",\n        \"LED Color Saturation\"\n      ]\n    },\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"LED Color Saturation\",\n        \"Macro\",\n        \"LED Speed\",\n        \"Channel Functions\",\n        \"Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/phantom-3r-beam.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Phantom 3R Beam\",\n  \"shortName\": \"Phant3RBeam\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2019-07-26\",\n    \"lastModifyDate\": \"2019-07-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://assets.highlite.com/attachments/MANUAL/40076_MANUAL_GB_V2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/40076-phantom-3r-beam.html\"\n    ],\n    \"video\": [\n      \"https://vimeo.com/211455354\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [325, 420, 210],\n    \"weight\": 12.5,\n    \"power\": 255,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 3R/150W\",\n      \"colorTemperature\": 8600\n    },\n    \"lens\": {\n      \"degreesMinMax\": [3.5, 3.5]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0042\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffe300\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff48\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#00abff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#b600ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Lime\",\n          \"colors\": [\"#e0ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0071ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#9200ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#76ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTO\",\n          \"colors\": [\"#ffeb85\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"½ CTO\",\n          \"colors\": [\"#fffea0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"CTB\",\n          \"colors\": [\"#549dff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#bd02ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"UV\",\n          \"colors\": [\"#7400ff\"]\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [132, 167],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [168, 203],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [204, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [240, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10.5\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11.5\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12.5\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13.5\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14.5\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15.5\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Static Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 14\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 15\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 16\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 17\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 18\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 18,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 17,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 16,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 15,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 14,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [144, 199],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 12],\n          \"type\": \"Prism\",\n          \"comment\": \"16-facet\"\n        },\n        {\n          \"dmxRange\": [13, 120],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [121, 247],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Prism\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Frost\": {\n      \"capability\": {\n        \"type\": \"Frost\",\n        \"frostIntensityStart\": \"off\",\n        \"frostIntensityEnd\": \"high\"\n      }\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled program 8\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Channel functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during color wheel movement\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt and color wheel movement\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt and gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt and wheels movement\"\n        },\n        {\n          \"dmxRange\": [56, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp on\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan reset\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt reset\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Color Wheel reset\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Gobo Wheel reset\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Frost reset\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Prism reset\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Focus reset\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\"\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Strobe reset\"\n        },\n        {\n          \"dmxRange\": [168, 231],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Lamp off\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Static Gobo Wheel\",\n        \"Prism\",\n        \"Focus\",\n        \"Frost\",\n        \"Programs\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Static Gobo Wheel\",\n        \"Prism\",\n        \"Focus\",\n        \"Frost\",\n        \"Channel functions\",\n        \"Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/phantom-50-led-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Phantom 50 LED Spot\",\n  \"shortName\": \"Phant50\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"Flo Edelmann\"],\n    \"createDate\": \"2017-04-29\",\n    \"lastModifyDate\": \"2020-02-11\"\n  },\n  \"comment\": \"Ordercode 40187\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/40187_MANUAL_GB_V1.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Z2YgfTfpUQo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [225, 340, 210],\n    \"weight\": 5.64,\n    \"power\": 185,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 1298\n    },\n    \"lens\": {\n      \"degreesMinMax\": [17, 17]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#fef201\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#c600ce\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#017f01\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#941e30\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#0155e9\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Green\",\n          \"colors\": [\"#01c702\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ca450c\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\",\n          \"colors\": [\"#2921d3\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/glass-red-10-circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/glass-raindrops-on-window\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/3-fold-swirl\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/biohazard\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/rose-petal\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/triangle-hexagon-pattern\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/dot-spiral\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [56, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [65, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [72, 78],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [79, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [86, 92],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [93, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [100, 106],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [107, 113],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [114, 120],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [121, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 255,\n      \"highlightValue\": 200,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Intensity\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Gobo\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 119],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [120, 231],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\",\n          \"menuClick\": \"center\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"isShaking\": \"slot\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"3-facet\"\n        }\n      ]\n    },\n    \"Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 27],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Pan/Tilt\"\n        },\n        {\n          \"dmxRange\": [28, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Gobowheel\"\n        },\n        {\n          \"dmxRange\": [48, 67],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while Pan/Tilt/Gobowheel\"\n        },\n        {\n          \"dmxRange\": [68, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Colorwheel\"\n        },\n        {\n          \"dmxRange\": [88, 107],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while Pan/Tilt/Colorwheel\"\n        },\n        {\n          \"dmxRange\": [108, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while Gobowheel/Colorwheel\"\n        },\n        {\n          \"dmxRange\": [128, 147],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disabled blackout while Pan/Tilt/Gobowheel/Colorwheel\"\n        },\n        {\n          \"dmxRange\": [148, 157],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan\"\n        },\n        {\n          \"dmxRange\": [158, 167],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Tilt\"\n        },\n        {\n          \"dmxRange\": [168, 177],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Colorwheel\"\n        },\n        {\n          \"dmxRange\": [178, 187],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Gobowheel\"\n        },\n        {\n          \"dmxRange\": [188, 197],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Prism\"\n        },\n        {\n          \"dmxRange\": [198, 207],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all channels\"\n        },\n        {\n          \"dmxRange\": [208, 255],\n          \"type\": \"NoFunction\",\n          \"menuClick\": \"hidden\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in Program 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled Program 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Advanced 13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color Wheel\",\n        \"Strobe\",\n        \"Intensity\",\n        \"Gobo\",\n        \"Gobo Rotation\",\n        \"Prism\",\n        \"Functions\",\n        \"Programs\"\n      ]\n    },\n    {\n      \"name\": \"Basic 8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Strobe\",\n        \"Intensity\",\n        \"Gobo\",\n        \"Gobo Rotation\",\n        \"Prism\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/phantom-matrix-fx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Phantom Matrix FX\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Saeckel1\"],\n    \"createDate\": \"2020-02-11\",\n    \"lastModifyDate\": \"2020-02-11\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://assets.highlite.com/attachments/MANUAL/40062_MANUAL_GB_V1.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/40062-phantom-matrix-fx.html\"\n    ],\n    \"video\": [\n      \"https://vimeo.com/211297960\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [445, 530, 200],\n    \"weight\": 9.8,\n    \"power\": 140,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"25× 4W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [45, 45]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [5, 5, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 128],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"comment\": \"FX\"\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\",\n          \"comment\": \"linear\"\n        }\n      ]\n    },\n    \"Linear Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        }\n      ]\n    },\n    \"FX Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"10Hz\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 13],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1 (R=255)\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2 (R=255 W=100)\",\n          \"colors\": [\"#ff4848\"]\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3 (R=255 W=200)\",\n          \"colors\": [\"#ff7070\"]\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4 (R=255 G=50)\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5 (R=255 G=150)\",\n          \"colors\": [\"#ff9600\"]\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6 (R=255 G=255)\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7 (R=255 G=255 W=75)\",\n          \"colors\": [\"#ffff3a\"]\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8 (G=255 W=255)\",\n          \"colors\": [\"#80ff80\"]\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9 (G=255 W=150)\",\n          \"colors\": [\"#5eff5e\"]\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10 (G=255 W=50)\",\n          \"colors\": [\"#2aff2a\"]\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11 (G=255)\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [84, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12 (G=255 B=50)\",\n          \"colors\": [\"#00ff32\"]\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13 (G=255 B=150)\",\n          \"colors\": [\"#00ff96\"]\n        },\n        {\n          \"dmxRange\": [98, 104],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14 (G=255 B=255)\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [105, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 15 (G=255 B=255 W=75)\",\n          \"colors\": [\"#3affff\"]\n        },\n        {\n          \"dmxRange\": [112, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 16 (G=255 B=255 W=150)\",\n          \"colors\": [\"#5effff\"]\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 17 (G=100 B=255 W=255)\",\n          \"colors\": [\"#80b2ff\"]\n        },\n        {\n          \"dmxRange\": [126, 132],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 18 (B=255 W=100)\",\n          \"colors\": [\"#4848ff\"]\n        },\n        {\n          \"dmxRange\": [133, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 19 (B=255 W=50)\",\n          \"colors\": [\"#2a2aff\"]\n        },\n        {\n          \"dmxRange\": [140, 146],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 20 (B=255)\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [147, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 21 (R=75 B=255)\",\n          \"colors\": [\"#4b00ff\"]\n        },\n        {\n          \"dmxRange\": [154, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 22 (R=160 B=255)\",\n          \"colors\": [\"#a000ff\"]\n        },\n        {\n          \"dmxRange\": [161, 167],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 23 (R=255 B=255)\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [168, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 24 (R=255 B=175)\",\n          \"colors\": [\"#ff00af\"]\n        },\n        {\n          \"dmxRange\": [175, 181],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 25 (R=255 B=100)\",\n          \"colors\": [\"#ff0064\"]\n        },\n        {\n          \"dmxRange\": [182, 188],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 26 (R=255 B=100 W=50)\",\n          \"colors\": [\"#ff2a7d\"]\n        },\n        {\n          \"dmxRange\": [189, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 27 (R=255 B=25 W=50)\",\n          \"colors\": [\"#ff2a3f\"]\n        },\n        {\n          \"dmxRange\": [196, 202],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 28 (R=255 B=25 W=25)\",\n          \"colors\": [\"#ff172e\"]\n        },\n        {\n          \"dmxRange\": [203, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 29 (R=255 B=25)\",\n          \"colors\": [\"#ff0019\"]\n        },\n        {\n          \"dmxRange\": [210, 216],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 30 (W=255)\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [217, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 31 (R=75 G=75 W=255)\",\n          \"colors\": [\"#ffffc5\"]\n        },\n        {\n          \"dmxRange\": [224, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 32 (B=100 W=255)\",\n          \"colors\": [\"#b7b7ff\"]\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 33 (R=255 G=255 B=255 W=255)\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Effect Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 12],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [13, 24],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [25, 36],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [37, 48],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [49, 60],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [61, 72],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [73, 84],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [85, 96],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [97, 108],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"8\"\n        },\n        {\n          \"dmxRange\": [109, 120],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"1\"\n        },\n        {\n          \"dmxRange\": [121, 132],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"2\"\n        },\n        {\n          \"dmxRange\": [133, 144],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3\"\n        },\n        {\n          \"dmxRange\": [145, 156],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"4\"\n        },\n        {\n          \"dmxRange\": [157, 168],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"5\"\n        },\n        {\n          \"dmxRange\": [169, 180],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"6\"\n        },\n        {\n          \"dmxRange\": [181, 192],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7\"\n        },\n        {\n          \"dmxRange\": [193, 204],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Rainbow 1\"\n        },\n        {\n          \"dmxRange\": [205, 216],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"Rainbow 2\"\n        },\n        {\n          \"dmxRange\": [217, 228],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"blue-red\"\n        },\n        {\n          \"dmxRange\": [229, 240],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"blue-green\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"yellow-red\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Pattern\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"0\"\n        },\n        {\n          \"dmxRange\": [11, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"1\"\n        },\n        {\n          \"dmxRange\": [14, 16],\n          \"type\": \"Effect\",\n          \"effectName\": \"2\"\n        },\n        {\n          \"dmxRange\": [17, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"3\"\n        },\n        {\n          \"dmxRange\": [20, 22],\n          \"type\": \"Effect\",\n          \"effectName\": \"4\"\n        },\n        {\n          \"dmxRange\": [23, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"5\"\n        },\n        {\n          \"dmxRange\": [26, 28],\n          \"type\": \"Effect\",\n          \"effectName\": \"6\"\n        },\n        {\n          \"dmxRange\": [29, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"7\"\n        },\n        {\n          \"dmxRange\": [32, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"8\"\n        },\n        {\n          \"dmxRange\": [35, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"9\"\n        },\n        {\n          \"dmxRange\": [38, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"A\"\n        },\n        {\n          \"dmxRange\": [41, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"B\"\n        },\n        {\n          \"dmxRange\": [44, 46],\n          \"type\": \"Effect\",\n          \"effectName\": \"C\"\n        },\n        {\n          \"dmxRange\": [47, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"D\"\n        },\n        {\n          \"dmxRange\": [50, 52],\n          \"type\": \"Effect\",\n          \"effectName\": \"E\"\n        },\n        {\n          \"dmxRange\": [53, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"F\"\n        },\n        {\n          \"dmxRange\": [56, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"G\"\n        },\n        {\n          \"dmxRange\": [59, 61],\n          \"type\": \"Effect\",\n          \"effectName\": \"H\"\n        },\n        {\n          \"dmxRange\": [62, 64],\n          \"type\": \"Effect\",\n          \"effectName\": \"I\"\n        },\n        {\n          \"dmxRange\": [65, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"J\"\n        },\n        {\n          \"dmxRange\": [68, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"K\"\n        },\n        {\n          \"dmxRange\": [71, 73],\n          \"type\": \"Effect\",\n          \"effectName\": \"L\"\n        },\n        {\n          \"dmxRange\": [74, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"M\"\n        },\n        {\n          \"dmxRange\": [77, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"N\"\n        },\n        {\n          \"dmxRange\": [80, 82],\n          \"type\": \"Effect\",\n          \"effectName\": \"O\"\n        },\n        {\n          \"dmxRange\": [83, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"P\"\n        },\n        {\n          \"dmxRange\": [86, 88],\n          \"type\": \"Effect\",\n          \"effectName\": \"Q\"\n        },\n        {\n          \"dmxRange\": [89, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"R\"\n        },\n        {\n          \"dmxRange\": [92, 94],\n          \"type\": \"Effect\",\n          \"effectName\": \"S\"\n        },\n        {\n          \"dmxRange\": [95, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"T\"\n        },\n        {\n          \"dmxRange\": [98, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"U\"\n        },\n        {\n          \"dmxRange\": [101, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"V\"\n        },\n        {\n          \"dmxRange\": [104, 106],\n          \"type\": \"Effect\",\n          \"effectName\": \"W\"\n        },\n        {\n          \"dmxRange\": [107, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"X\"\n        },\n        {\n          \"dmxRange\": [110, 112],\n          \"type\": \"Effect\",\n          \"effectName\": \"Y\"\n        },\n        {\n          \"dmxRange\": [113, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Z\"\n        },\n        {\n          \"dmxRange\": [116, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 1\"\n        },\n        {\n          \"dmxRange\": [119, 121],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 2\"\n        },\n        {\n          \"dmxRange\": [122, 124],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 3\"\n        },\n        {\n          \"dmxRange\": [125, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 4\"\n        },\n        {\n          \"dmxRange\": [128, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 5\"\n        },\n        {\n          \"dmxRange\": [131, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 6\"\n        },\n        {\n          \"dmxRange\": [134, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 7\"\n        },\n        {\n          \"dmxRange\": [137, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 8\"\n        },\n        {\n          \"dmxRange\": [140, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 9\"\n        },\n        {\n          \"dmxRange\": [143, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 10\"\n        },\n        {\n          \"dmxRange\": [146, 148],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 11\"\n        },\n        {\n          \"dmxRange\": [149, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 12\"\n        },\n        {\n          \"dmxRange\": [152, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 13\"\n        },\n        {\n          \"dmxRange\": [155, 157],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 14\"\n        },\n        {\n          \"dmxRange\": [158, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 15\"\n        },\n        {\n          \"dmxRange\": [161, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 16\"\n        },\n        {\n          \"dmxRange\": [164, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 17\"\n        },\n        {\n          \"dmxRange\": [167, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 18\"\n        },\n        {\n          \"dmxRange\": [170, 172],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 19\"\n        },\n        {\n          \"dmxRange\": [173, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 20\"\n        },\n        {\n          \"dmxRange\": [176, 178],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 21\"\n        },\n        {\n          \"dmxRange\": [179, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 22\"\n        },\n        {\n          \"dmxRange\": [182, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 23\"\n        },\n        {\n          \"dmxRange\": [185, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 24\"\n        },\n        {\n          \"dmxRange\": [188, 190],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 25\"\n        },\n        {\n          \"dmxRange\": [191, 193],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 26\"\n        },\n        {\n          \"dmxRange\": [194, 196],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 27\"\n        },\n        {\n          \"dmxRange\": [197, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 28\"\n        },\n        {\n          \"dmxRange\": [200, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 29\"\n        },\n        {\n          \"dmxRange\": [203, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 30\"\n        },\n        {\n          \"dmxRange\": [206, 208],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 31\"\n        },\n        {\n          \"dmxRange\": [209, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 32\"\n        },\n        {\n          \"dmxRange\": [212, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 33\"\n        },\n        {\n          \"dmxRange\": [215, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 34\"\n        },\n        {\n          \"dmxRange\": [218, 220],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 35\"\n        },\n        {\n          \"dmxRange\": [221, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 36\"\n        },\n        {\n          \"dmxRange\": [224, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 37\"\n        },\n        {\n          \"dmxRange\": [227, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 38\"\n        },\n        {\n          \"dmxRange\": [230, 232],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 39\"\n        },\n        {\n          \"dmxRange\": [233, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 40\"\n        },\n        {\n          \"dmxRange\": [236, 238],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 41\"\n        },\n        {\n          \"dmxRange\": [239, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 42\"\n        },\n        {\n          \"dmxRange\": [242, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 43\"\n        },\n        {\n          \"dmxRange\": [245, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 44\"\n        },\n        {\n          \"dmxRange\": [248, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 45\"\n        },\n        {\n          \"dmxRange\": [251, 253],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 46\"\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 47\"\n        }\n      ]\n    },\n    \"Pattern Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 1\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 2\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 3\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 4\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 5\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 6\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 7\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Show 8\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Generic\",\n          \"comment\": \"Slave 1\"\n        },\n        {\n          \"dmxRange\": [91, 96],\n          \"type\": \"Generic\",\n          \"comment\": \"Slave 2\"\n        },\n        {\n          \"dmxRange\": [97, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [161, 170],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan inversion\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [171, 180],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt inversion\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [181, 190],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan normal\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [191, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt normal\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [201, 220],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt blackout on\"\n        },\n        {\n          \"dmxRange\": [221, 240],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt blackout off\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-Channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Effect Macros\",\n        \"Effect Speed\",\n        \"Pattern\",\n        \"Pattern Speed\",\n        \"Function\"\n      ]\n    },\n    {\n      \"name\": \"18-Channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Linear Strobe\",\n        \"FX Strobe\",\n        \"Color Macros\",\n        \"Effect Macros\",\n        \"Effect Speed\",\n        \"Pattern\",\n        \"Pattern Speed\",\n        \"Function\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"118-Channel\",\n      \"shortName\": \"118ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Linear Strobe\",\n        \"FX Strobe\",\n        \"Color Macros\",\n        \"Effect Macros\",\n        \"Effect Speed\",\n        \"Pattern\",\n        \"Pattern Speed\",\n        \"Function\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/pixel-bar-12-mkii.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Pixel Bar 12 MKII\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-08\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/41304_MANUAL_GB_V1.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=C52A9mJ3McY\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1070, 135, 75],\n    \"weight\": 3.88,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x RGB 3W LEDs\",\n      \"lumens\": 1380\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"12\", \"11\", \"10\", \"9\", \"8\", \"7\", \"6\", \"5\", \"4\", \"3\", \"2\", \"1\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": { \"x\": [\">=7\"] },\n      \"2/2\": { \"x\": [\"<=6\"] },\n      \"1/3\": [\"1\", \"2\", \"3\", \"4\"],\n      \"2/3\": [\"5\", \"6\", \"7\", \"8\"],\n      \"3/3\": [\"9\", \"10\", \"11\", \"12\"],\n      \"1/4\": [\"1\", \"2\", \"3\"],\n      \"2/4\": [\"4\", \"5\", \"6\"],\n      \"3/4\": [\"7\", \"8\", \"9\"],\n      \"4/4\": [\"10\", \"11\", \"12\"],\n      \"1/6\": [\"1\", \"2\"],\n      \"2/6\": [\"3\", \"4\"],\n      \"3/6\": [\"5\", \"6\"],\n      \"4/6\": [\"7\", \"8\"],\n      \"5/6\": [\"9\", \"10\"],\n      \"6/6\": [\"11\", \"12\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [63, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 76],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [77, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [84, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [98, 104],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [105, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 118],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [119, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [126, 132],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [133, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [147, 153],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 21\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 22\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 23\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 24\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [175, 181],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 25\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [182, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 26\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [189, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 27\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [196, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 28\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [203, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 29\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 216],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 30\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [217, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 31\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 32\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [231, 237],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 33\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [238, 244],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 34\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [245, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 35\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"11Hz\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"RGBD\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Master Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"RGB Halves\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/2\", \"2/2\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGBD + Effects\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Master Dimmer\",\n        \"Programs\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"RGB Thirds\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/3\", \"2/3\", \"3/3\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Quarters\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/4\", \"2/4\", \"3/4\", \"4/4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Sixths\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1/6\", \"2/6\", \"3/6\", \"4/6\", \"5/6\", \"6/6\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"RGB Individual\",\n      \"shortName\": \"36ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/shark-the-meg-hybrid-one.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Shark The Meg Hybrid One\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"David Huss\", \"Flo Edelmann\"],\n    \"createDate\": \"2026-01-27\",\n    \"lastModifyDate\": \"2026-01-27\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.showtec-lights.com/en/mwdownloads/download/link/id/17451689\"\n    ],\n    \"productPage\": [\n      \"https://www.showtec-lights.com/en/45041-shark-the-meg-hybrid-one.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=mKnNAuy2t4c\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [283, 165, 435],\n    \"weight\": 9.85,\n    \"power\": 200,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 3075\n    },\n    \"lens\": {\n      \"name\": \"Motorised Lens\",\n      \"degreesMinMax\": [3.8, 15.8]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 1\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 2\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 3\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 4\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 5\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 6\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 7\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 8\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Color 9\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 7\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 1\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 7\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 8\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 9\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 10\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 11\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 12\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"210deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 225],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on PT move\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout on Color/Gobo move\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"soundControlled\": true,\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [128, 144],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [145, 159],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Channel Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 79],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"off\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset all motors\"\n        },\n        {\n          \"dmxRange\": [85, 87],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"off\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset pan & tilt\"\n        },\n        {\n          \"dmxRange\": [88, 90],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"off\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset color wheel\"\n        },\n        {\n          \"dmxRange\": [91, 93],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"off\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset gobo wheel\"\n        },\n        {\n          \"dmxRange\": [94, 96],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [97, 99],\n          \"type\": \"Maintenance\",\n          \"parameter\": \"off\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset other motors\"\n        },\n        {\n          \"dmxRange\": [100, 108],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\"\n        },\n        {\n          \"dmxRange\": [109, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\"\n        },\n        {\n          \"dmxRange\": [118, 126],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\"\n        },\n        {\n          \"dmxRange\": [127, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\"\n        },\n        {\n          \"dmxRange\": [136, 144],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 5\"\n        },\n        {\n          \"dmxRange\": [145, 153],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 6\"\n        },\n        {\n          \"dmxRange\": [154, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 7\"\n        },\n        {\n          \"dmxRange\": [163, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 8\"\n        },\n        {\n          \"dmxRange\": [172, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [181, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [190, 198],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [199, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [208, 216],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [217, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [226, 234],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [235, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program 8\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [80, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [85, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [90, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [128, 189],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [190, 193],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [194, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel 1\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [140, 159],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [160, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [220, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [132, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel 2\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel 2\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 10\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 11\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 12\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 13\n        },\n        {\n          \"dmxRange\": [130, 137],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [138, 145],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [146, 153],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [154, 161],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [162, 169],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [170, 177],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [178, 185],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [186, 193],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 9,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [194, 201],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 10,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [202, 209],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 11,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [210, 217],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 12,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [218, 225],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 13,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [226, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Prism Off\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Prism\",\n          \"comment\": \"Prism On (3-facet)\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\",\n          \"comment\": \"Manual does not specify rotation direction\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Frost\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"off\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Frost\",\n          \"frostIntensity\": \"high\"\n        }\n      ]\n    },\n    \"Color Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"short\",\n        \"timeEnd\": \"long\",\n        \"comment\": \"Color Change Time\"\n      }\n    },\n    \"Gobo Time\": {\n      \"capability\": {\n        \"type\": \"Time\",\n        \"timeStart\": \"short\",\n        \"timeEnd\": \"long\",\n        \"comment\": \"Gobo change time\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Focus\",\n        \"Zoom\",\n        \"Channel Functions\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel 1\",\n        \"Gobo Rotation\",\n        \"Gobo Wheel 2\",\n        \"Focus\",\n        \"Zoom\",\n        \"Prism\",\n        \"Frost\",\n        \"Channel Functions\"\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel 1\",\n        \"Gobo Rotation\",\n        \"Gobo Wheel 2\",\n        \"Focus\",\n        \"Zoom\",\n        \"Prism\",\n        \"Frost\",\n        \"Channel Functions\",\n        \"Color Time\",\n        \"Gobo Time\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/sunraise-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Sunraise LED\",\n  \"categories\": [\"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-06\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/43078_MANUAL_GB_V2.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=0OWjGQxuBY8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [266, 260, 266],\n    \"weight\": 2.8,\n    \"power\": 35,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"55 x 3W RGBWA LEDs\",\n      \"lumens\": 1000\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#000000\"],\n          \"comment\": \"Black\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\"],\n          \"comment\": \"Red + Green\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"],\n          \"comment\": \"Red + Blue\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffffff\"],\n          \"comment\": \"Red + White\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#ffbf00\"],\n          \"comment\": \"Red + Amber\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Green + Blue\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ffffff\"],\n          \"comment\": \"Green + White\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\", \"#ffbf00\"],\n          \"comment\": \"Green + Amber\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Blue + White\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\", \"#ffbf00\"],\n          \"comment\": \"White + Amber\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\"],\n          \"comment\": \"Red + Green + Blue\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\"],\n          \"comment\": \"Red + Green + Blue + White\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffbf00\"],\n          \"comment\": \"Red + Green + Blue + Amber\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ffffff\", \"#ffbf00\"],\n          \"comment\": \"Red + Green + Blue + White + Amber\"\n        },\n        {\n          \"dmxRange\": [200, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto\"\n        },\n        {\n          \"dmxRange\": [230, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"12Hz\"\n        }\n      ]\n    },\n    \"Auto Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Motor Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 119],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Rotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [130, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Strobe\",\n        \"Auto Speed\",\n        \"Motor Rotation\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/sunstrip-active-mkii.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Sunstrip Active MKII\",\n  \"shortName\": \"SunstripActiveMKII\",\n  \"categories\": [\"Pixel Bar\", \"Blinder\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Voyo\"],\n    \"createDate\": \"2018-11-02\",\n    \"lastModifyDate\": \"2018-11-02\"\n  },\n  \"comment\": \"The Sunstrip Active DMX MKII is the successor to the Showtec Sunstrip Active. For stand-alone applications, the Sunstrip Active is equipped with 16 built-in patterns as well as a manual dimmer. With the Neutrik power twist in- and outputs, the Sunstrip is also ideal for more demanding on-the-road purposes. It is equipped with two wall / floor brackets, as well as several M10 nuts to position the clamp in the desired position.\\nOrdercode: 30714\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/30714_MANUAL_GB_V2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.highlite.com/en/30714-sunstrip-active-mkii.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=LuGJksbKqcg\",\n      \"https://www.youtube.com/watch?v=xvT7drytw00\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1080, 130, 130],\n    \"weight\": 6.2,\n    \"power\": 550,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"10 x 240V/50W GU10\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [35, 35]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [10, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"1/2\": [\"1\", \"2\", \"3\", \"4\", \"5\"],\n      \"2/2\": [\"6\", \"7\", \"8\", \"9\", \"10\"],\n      \"1/5\": [\"1\", \"2\"],\n      \"2/5\": [\"3\", \"4\"],\n      \"3/5\": [\"5\", \"6\"],\n      \"4/5\": [\"7\", \"8\"],\n      \"5/5\": [\"9\", \"10\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Master\",\n      \"shortName\": \"1x10\",\n      \"channels\": [\n        \"Dimmer Master\"\n      ]\n    },\n    {\n      \"name\": \"Halves\",\n      \"shortName\": \"2x5\",\n      \"channels\": [\n        \"Dimmer 1/2\",\n        \"Dimmer 2/2\"\n      ]\n    },\n    {\n      \"name\": \"Fifths\",\n      \"shortName\": \"5x2\",\n      \"channels\": [\n        \"Dimmer 1/5\",\n        \"Dimmer 2/5\",\n        \"Dimmer 3/5\",\n        \"Dimmer 4/5\",\n        \"Dimmer 5/5\"\n      ]\n    },\n    {\n      \"name\": \"Individual\",\n      \"shortName\": \"10x1\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Dimmer $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showtec/xs-1-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"XS-1 RGBW\",\n  \"shortName\": \"ShowtecXS1\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Jo\"],\n    \"createDate\": \"2018-05-28\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.highlite.com/media/attachments/MANUAL/40159_MANUAL_GB_V1.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=G7dkpbHmG8s\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [125, 236, 125],\n    \"weight\": 2,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"10W RGBW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [3, 3]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Pan/Tilt Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 1\"\n        },\n        {\n          \"dmxRange\": [36, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 2\"\n        },\n        {\n          \"dmxRange\": [56, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 3\"\n        },\n        {\n          \"dmxRange\": [76, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 4\"\n        },\n        {\n          \"dmxRange\": [96, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 5\"\n        },\n        {\n          \"dmxRange\": [116, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 6\"\n        },\n        {\n          \"dmxRange\": [136, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 7\"\n        },\n        {\n          \"dmxRange\": [156, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 8\"\n        },\n        {\n          \"dmxRange\": [176, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 9\"\n        },\n        {\n          \"dmxRange\": [196, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 10\"\n        },\n        {\n          \"dmxRange\": [216, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 11\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Macro 12\"\n        }\n      ]\n    },\n    \"Pan/Tilt Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"durationStart\": \"long\",\n          \"durationEnd\": \"short\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Channel Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Enable Pan/tilt blackout\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Disable Pan/tilt blackout\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [90, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Color Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static Colors\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Dimmer\",\n        \"Channel Functions\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Pan/Tilt Macros\",\n        \"Pan/Tilt Macro Speed\",\n        \"Channel Functions\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Shutter / Strobe\",\n        \"Color Programs\",\n        \"Program Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showven/sparkular-fall.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Sparkular Fall (BT04)\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Alejo Cervera\"],\n    \"createDate\": \"2018-06-13\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.vlammen.com/sparkular/Sparkular%20fall.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.sparkular-fx.com/index.php/en/unkategorisiert/sparkular/sparkular-fall-bt04-2\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=_vun0DvkvgY\",\n      \"https://www.youtube.com/watch?v=nCAtCLBoXxs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [192, 208, 192],\n    \"weight\": 6,\n    \"power\": 400,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Fountain\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"HTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Fountain off\"\n        },\n        {\n          \"dmxRange\": [16, 135],\n          \"type\": \"EffectParameter\",\n          \"parameter\": \"low\",\n          \"comment\": \"Fountain level\"\n        },\n        {\n          \"dmxRange\": [136, 255],\n          \"type\": \"EffectParameter\",\n          \"parameter\": \"high\",\n          \"comment\": \"Fountain level\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pre-Heat OFF\"\n        },\n        {\n          \"dmxRange\": [11, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Emergency Stop\"\n        },\n        {\n          \"dmxRange\": [41, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Clear Material\"\n        },\n        {\n          \"dmxRange\": [81, 239],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pre-Heat ON\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Default\",\n      \"channels\": [\n        \"Fountain\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/showven/sparkular.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Sparkular (BT01)\",\n  \"shortName\": \"Sparkular\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Alejo Cervera\"],\n    \"createDate\": \"2018-06-13\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://www.vlammen.com/sparkular/Sparkular%20Manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.sparkular-fx.com/index.php/en/unkategorisiert/sparkular/sparkular-2\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=U1PnWVvIn2w\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 215, 285],\n    \"weight\": 8.5,\n    \"power\": 365,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Fountain\": {\n      \"precedence\": \"HTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Fountain Off\"\n        },\n        {\n          \"dmxRange\": [16, 39],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 1,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [40, 63],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 2,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [64, 87],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 3,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [88, 111],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 4,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [112, 135],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 5,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [136, 159],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 6,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [160, 183],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 7,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [184, 207],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 8,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [208, 231],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 9,\n          \"comment\": \"Height\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"EffectParameter\",\n          \"parameter\": 10,\n          \"comment\": \"Height\"\n        }\n      ]\n    },\n    \"Control\": {\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pre-Heat OFF\"\n        },\n        {\n          \"dmxRange\": [11, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"EMERGENCY STOP\"\n        },\n        {\n          \"dmxRange\": [41, 59],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [60, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Clear Material\"\n        },\n        {\n          \"dmxRange\": [81, 239],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pre-Heat ON\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Default\",\n      \"channels\": [\n        \"Fountain\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/silver-star/mx-indigo-6000xe.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MX-Indigo 6000XE\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Khors\"],\n    \"createDate\": \"2019-10-26\",\n    \"lastModifyDate\": \"2019-10-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://file001.shop-pro.jp/PA01017/727/silverstar/ss_indg6000xe_mnl.pdf\"\n    ],\n    \"productPage\": [\n      \"http://www.show-light.ru/svetovoe-oborudovanie/svetodiodnye-oborydovanie-led/pribory-polnogo-vrashcheniya-led/silver-star-yg-led621xwa-mx-indigo-6000-xe-povorotnaya-golova-detail\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=5PMrgbFYnJo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [339, 433, 252],\n    \"weight\": 11,\n    \"power\": 330,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"91 LEDs (22× red, 23× green, 22× blue, 12× white, 12× amber)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Maximum output\"\n        },\n        {\n          \"dmxRange\": [11, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [31, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#ffff00\"],\n          \"colorsEnd\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Cyan\",\n          \"colorsStart\": [\"#00ff00\"],\n          \"colorsEnd\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [71, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan … Blue\",\n          \"colorsStart\": [\"#00ffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [91, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#0000ff\"],\n          \"colorsEnd\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [111, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#ff00ff\"],\n          \"colorsEnd\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [131, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … White\",\n          \"colorsStart\": [\"#ff0000\"],\n          \"colorsEnd\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [151, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White … Blue\",\n          \"colorsStart\": [\"#ffffff\"],\n          \"colorsEnd\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [171, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + White 100%\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 1\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 2\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 3\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 4\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4900K\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 5\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 6\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5900K\"\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 7\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [236, 240],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 8\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 9\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 10\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8500K\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White 11\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt blackout ON\"\n        },\n        {\n          \"dmxRange\": [40, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan/Tilt blackout OFF\"\n        },\n        {\n          \"dmxRange\": [60, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan auto\"\n        },\n        {\n          \"dmxRange\": [80, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan slow\"\n        },\n        {\n          \"dmxRange\": [100, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan normal\"\n        },\n        {\n          \"dmxRange\": [120, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan fast\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Auto 1\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Auto 2\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Test\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Custom\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [180, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tone 1\"\n        },\n        {\n          \"dmxRange\": [200, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"3s\"\n        },\n        {\n          \"dmxRange\": [220, 235],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed DIM0 (fastest)\"\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed DIM1\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed DIM2\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed DIM3\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed DIM4 (slowest)\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Advanced 15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Color Macros\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"Basic 12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Color Macros\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Zoom\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/skypix/ribalta-beam.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Ribalta Beam\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"txukinho\", \"pedro hugo\", \"Felix Edelmann\"],\n    \"createDate\": \"2018-10-16\",\n    \"lastModifyDate\": \"2018-10-16\"\n  },\n  \"links\": {\n    \"video\": [\n      \"https://www.youtube.com/watch?v=5DTkpKhS_kE\"\n    ]\n  },\n  \"helpWanted\": \"The 38-channel mode, channel data and a link to the manual are missing. Is this fixture the same as the ETEC LED Roto Bar?\",\n  \"physical\": {\n    \"bulb\": {\n      \"type\": \"8x 10W RGBW LEDs\"\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [8, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Tilt\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Auto\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"helpWanted\": \"What does this channel do?\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\",\n        \"helpWanted\": \"Is it low…high or high…low?\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Tilt\",\n        \"Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Auto\",\n        \"Sound Sensitivity\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/smoke-factory/data-ii.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Data II\",\n  \"shortName\": \"Data2\",\n  \"categories\": [\"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"WaldperlachFabi\"],\n    \"createDate\": \"2023-07-10\",\n    \"lastModifyDate\": \"2023-07-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://smoke-factory.de/pdf/datenblatt_data_ii.pdf\"\n    ],\n    \"productPage\": [\n      \"https://smoke-factory.de/produkt/data-ii/?lang=en\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [585, 230, 247],\n    \"weight\": 12.8,\n    \"power\": 2600,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Pump\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Fog\",\n        \"fogOutputStart\": \"weak\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Fan\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2ch\",\n      \"channels\": [\n        \"Pump\",\n        \"Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/smoke-factory/tour-hazer-ii.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Tour Hazer II\",\n  \"shortName\": \"TourHazer2\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"WaldperlachFabi\"],\n    \"createDate\": \"2023-07-10\",\n    \"lastModifyDate\": \"2023-07-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://smoke-factory.de/pdf/datenblatt_tour_hazer_ii.pdf\"\n    ],\n    \"productPage\": [\n      \"https://smoke-factory.de/product-categories/machines/hazer-en/?lang=en\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [550, 265, 415],\n    \"weight\": 16.5,\n    \"power\": 1500,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Pump\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Haze\",\n        \"fogOutputStart\": \"weak\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Fan\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2ch\",\n      \"channels\": [\n        \"Pump\",\n        \"Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/solaris/smart-36.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SMART 36\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"ziopix\"],\n    \"createDate\": \"2018-10-25\",\n    \"lastModifyDate\": \"2018-10-25\"\n  },\n  \"physical\": {\n    \"dimensions\": [118, 237, 230],\n    \"weight\": 3,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"36x 3W LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Mode Change\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Macro function\",\n        \"helpWanted\": \"Which macro is this and at which DMX value is it activated? Are there several macros to choose from?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Mode Change\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/solena/max-par-20.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Max Par 20\",\n  \"shortName\": \"SolMax20\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-11-02\",\n    \"lastModifyDate\": \"2018-11-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdn.shopify.com/s/files/1/0277/2631/5568/files/MAX-PAR-20-RGB-2.pdf\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20230929222841/https://www.pssl.com/products/solena-max-par-20-rgb-20-watt-dmx-led-wash-light\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=acCYbTfasMQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 180, 100],\n    \"weight\": 0.6,\n    \"power\": 18,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"20W LEDs (54x Red, 54x Green, 54x Blue)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color Selection / Effect Speed\": \"Color Selection\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Select\",\n          \"switchChannels\": {\n            \"Color Selection / Effect Speed\": \"Color Selection\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color shade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"switchChannels\": {\n            \"Color Selection / Effect Speed\": \"Color Selection\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color pulse transform\",\n          \"helpWanted\": \"The manual implies speed slow…fast in this capability, but also speed controlled by channel 'Effect Speed'. Which is correct here?\",\n          \"switchChannels\": {\n            \"Color Selection / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color transition\",\n          \"helpWanted\": \"The manual implies speed slow…fast in this capability, but also speed controlled by channel 'Effect Speed'. Which is correct here?\",\n          \"switchChannels\": {\n            \"Color Selection / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color Selection / Effect Speed\": \"Color Selection\"\n          }\n        }\n      ]\n    },\n    \"Color Selection\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"helpWanted\": \"At which DMX values can which colors be selected?\"\n      }\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-Channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Effect\",\n        \"Color Selection / Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/solena/mini-par-12.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mini Par 12\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ranaivo\", \"Felix Edelmann\"],\n    \"createDate\": \"2018-10-12\",\n    \"lastModifyDate\": \"2018-10-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://cdn.shopify.com/s/files/1/0277/2631/5568/files/MINI-PAR-12.pdf\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20221207234839/https://www.pssl.com/products/solena-mini-par-12-12x1-watt-rgbw-led-wash-light\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=qX840Po0jrE\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [137, 115, 153],\n    \"weight\": 0.3,\n    \"power\": 12,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 1W LEDs (3x red, 3x green, 3x blue, 3x white)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Change\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color Select / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static color\",\n          \"switchChannels\": {\n            \"Color Select / Program Speed\": \"Color Select\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 143],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"RGB\",\n          \"switchChannels\": {\n            \"Color Select / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"RGBW\",\n          \"switchChannels\": {\n            \"Color Select / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"RGBW\",\n          \"switchChannels\": {\n            \"Color Select / Program Speed\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true,\n          \"comment\": \"RGBW\",\n          \"switchChannels\": {\n            \"Color Select / Program Speed\": \"Program Speed\"\n          }\n        }\n      ]\n    },\n    \"Color Select\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"comment\": \"Colors 01…16\",\n        \"helpWanted\": \"At which DMX values can which colors be selected?\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [64, 223],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Change\",\n        \"Color Select / Program Speed\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/soundlight/3204r-h.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"3204R-H\",\n  \"shortName\": \"SoundLight3204R-H\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"LT-P\"],\n    \"createDate\": \"2019-06-03\",\n    \"lastModifyDate\": \"2019-06-03\"\n  },\n  \"comment\": \"DMX relay control. DMX connector is not XLR but a simple 3-pin wire connector.\",\n  \"links\": {\n    \"manual\": [\n      \"https://soundlight.de/produkte/manuals/3204r-h/english/3204r-h%20rdm%20mk1%20e.pdf\"\n    ],\n    \"productPage\": [\n      \"https://soundlight.de/produkte/3204r-h/index.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [86, 67, 90],\n    \"power\": 3,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Relay 1\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Relay 2\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Relay 3\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Relay 4\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Relay control\",\n      \"channels\": [\n        \"Relay 1\",\n        \"Relay 2\",\n        \"Relay 3\",\n        \"Relay 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stage-right/mini-beam-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mini Beam RGBW\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2019-12-23\",\n    \"lastModifyDate\": \"2019-12-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://downloads.monoprice.com/files/manuals/612980_Manual_180122.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.monoprice.com/product?p_id=612980\",\n      \"https://www.lixada.com/p-l1239eu.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 127, 122],\n    \"weight\": 2,\n    \"power\": 50,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"RGBW LED\"\n    },\n    \"lens\": {\n      \"name\": \"Fresnel\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0Hz\",\n        \"speedEnd\": \"18Hz\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Colors\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [31, 125],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [126, 249],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Reset\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Colors\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stage-right/stage-wash-7x10w-led-moving-head.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stage Wash 7x10W LED Moving Head\",\n  \"shortName\": \"StageRightWash7x10W-MH\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\", \"martin3000\", \"sirexeclp\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-03-29\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"comment\": \"This fixture is sold under different brands / names.\",\n  \"links\": {\n    \"manual\": [\n      \"https://downloads.monoprice.com/files/manuals/612870_Manual_170822.pdf\",\n      \"https://images-na.ssl-images-amazon.com/images/I/817xvVgs88L.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.monoprice.com/product?p_id=612870\",\n      \"https://www.lixada.com/p-l0761us.html\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=GOy2Memx1qQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [240, 300, 240],\n    \"weight\": 3.8,\n    \"power\": 80,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"7× 10W RGBW LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 134],\n          \"type\": \"Intensity\"\n        },\n        {\n          \"dmxRange\": [135, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 231],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"Seven Colors\"\n        }\n      ]\n    },\n    \"Color Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Auto / Sound Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode\",\n          \"speed\": \"fast\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode\",\n          \"speed\": \"slow\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 2\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 200],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"helpWanted\": \"How many seconds must that DMX value be set?\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Pan/Tilt Speed\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Presets\",\n        \"Color Effect Speed\",\n        \"Auto / Sound Mode\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/af-180-led-fogger.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"AF-180 LED Fogger\",\n  \"shortName\": \"AF 180\",\n  \"categories\": [\"Smoke\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"peaceman\"],\n    \"createDate\": \"2019-10-06\",\n    \"lastModifyDate\": \"2019-10-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.thomann.de/pics/atg/atgdata/document/manual/c_334044_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_af_180_led_fogger_co2_fx_dmx.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i2656p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [340, 190, 300],\n    \"weight\": 8.9,\n    \"power\": 850,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED (3× red, 3× green, 3× blue)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Fog\",\n          \"fogType\": \"Fog\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [21, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [36, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [66, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [81, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [96, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [111, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Fog\",\n        \"Dimmer\",\n        \"Color Presets\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/af-250.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"AF-250\",\n  \"categories\": [\"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"Jan Dalheimer\"],\n    \"createDate\": \"2019-09-09\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/340945_c_340945_v5_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_af_250_fog_machine_1300w_dmx.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i3289p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [310, 190, 430],\n    \"weight\": 7.1,\n    \"power\": 1300,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Fog\",\n        \"fogOutputStart\": \"0m^3/min\",\n        \"fogOutputEnd\": \"180m^3/min\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Fog\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/afh-600.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"AFH-600\",\n  \"shortName\": \"StairvilleAFH600\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"LordVonAdel\"],\n    \"createDate\": \"2019-08-26\",\n    \"lastModifyDate\": \"2019-08-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/306309_c_306309_r4_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_afh_600_dmx_hazer.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i4312p10_yd59vqpa.mp4\",\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i2169p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [290, 265, 450],\n    \"weight\": 5.5,\n    \"power\": 1290,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Haze\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Haze\",\n        \"fogOutputStart\": \"0m^3/min\",\n        \"fogOutputEnd\": \"850m^3/min\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Haze\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/bel6-ip-bar-hex.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BEL6 IP Bar HEX\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"B the pulp\", \"Flo Edelmann\"],\n    \"createDate\": \"2021-12-03\",\n    \"lastModifyDate\": \"2021-12-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/471167_c_471167_r2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_bel6_ip_bar_hex.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i8892p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [510, 100, 90],\n    \"weight\": 4.5,\n    \"power\": 70,\n    \"DMXconnector\": \"3-pin XLR IP65\",\n    \"bulb\": {\n      \"type\": \"6× 15W RGBAWUV LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Function Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 80],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which color can be selected at which DMX value?\"\n        },\n        {\n          \"dmxRange\": [81, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [151, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic sound-controlled show\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Function Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Function Selection\",\n        \"Function Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/clb5-2p-rgb-ww-compact-led-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"CLB5 2P RGB WW Compact LED Bar\",\n  \"categories\": [\"Stand\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Murph\", \"Flo Edelmann\"],\n    \"createDate\": \"2021-10-29\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_448711_v4_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_clb5_2p_rgb_ww_compact_led_bar.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [473, 253, 67],\n    \"weight\": 3.5,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"14× 4W RGBWW LEDs\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Spot 1\", \"Spot 2\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Warm White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [5, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Auto Shows\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 7],\n          \"type\": \"Generic\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Color Macros\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 01\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 02\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 03\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 04\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 05\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 06\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 07\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 08\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 09\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 10\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 11\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 12\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 13\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 14\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 15\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 16\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 17\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 18\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 19\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 20\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [168, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 21\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 22\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [184, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 23\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 24\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 25\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 26\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [216, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 27\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 28\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto show 29\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Sound-controlled show\",\n          \"switchChannels\": {\n            \"Color Macros / Show Speed / Sound Shows\": \"Sound Shows\"\n          }\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Black\",\n          \"colors\": [\"#000000\"]\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff9600\"]\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Orange\",\n          \"colors\": [\"#ffb400\"]\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff00bc\"]\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Red\",\n          \"colors\": [\"#ffd2d2\"]\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#d2ffd2\"]\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#d2d2ff\"]\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffd861\"]\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Full White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Show Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Shows\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 01\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 02\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 03\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [27, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 04\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [36, 44],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 05\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [45, 53],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 06\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [54, 62],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 07\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [63, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 08\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [72, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 09\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [81, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [90, 98],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [99, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [108, 116],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [117, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [126, 134],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [135, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 16\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [144, 152],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 17\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [153, 161],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 18\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [162, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 19\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [171, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 20\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [180, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 21\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [189, 197],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 22\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [198, 206],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 23\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [207, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 24\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 25\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [225, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 26\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [234, 242],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 27\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [243, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 28\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound show 29\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Warm White Master\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red Spot 1\",\n        \"Green Spot 1\",\n        \"Blue Spot 1\",\n        \"Warm White Spot 1\",\n        \"Red Spot 2\",\n        \"Green Spot 2\",\n        \"Blue Spot 2\",\n        \"Warm White Spot 2\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Spot 1\",\n        \"Green Spot 1\",\n        \"Blue Spot 1\",\n        \"Warm White Spot 1\",\n        \"Red Spot 2\",\n        \"Green Spot 2\",\n        \"Blue Spot 2\",\n        \"Warm White Spot 2\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red Spot 1\",\n        \"Green Spot 1\",\n        \"Blue Spot 1\",\n        \"Warm White Spot 1\",\n        \"Red Spot 2\",\n        \"Green Spot 2\",\n        \"Blue Spot 2\",\n        \"Warm White Spot 2\",\n        \"Auto Shows\",\n        \"Color Macros / Show Speed / Sound Shows\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/cx60-hex.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"CX60 Hex\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Leon Dietrich\", \"Flo Edelmann\"],\n    \"createDate\": \"2026-02-26\",\n    \"lastModifyDate\": \"2026-02-26\"\n  },\n  \"comment\": \"Stairville CX 60 Hex, LED-Par Lamp\",\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_469039_469040_469056_469058_523399_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_cx_60_hex.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=FAIM-LrFix4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [405, 275, 275],\n    \"weight\": 3.3,\n    \"power\": 170,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 6700,\n      \"lumens\": 8500\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Effect Speed - slow/fast\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"14 color automatic switching\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Effect Speed - slow/fast\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"24 color automatic switching\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Effect Speed - fast/slow\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"6 color automatic switching\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Effect Speed - slow/fast\": {\n      \"name\": \"Effect Speed\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect Speed - fast/slow\": {\n      \"name\": \"Effect Speed\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Color Pattern\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"EffectParameter\",\n          \"parameterStart\": \"low\",\n          \"parameterEnd\": \"high\",\n          \"comment\": \"Selection of color pattern (1/31)\"\n        }\n      ]\n    },\n    \"Strobe Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"comment\": \"This setting affects the Fade Control channel as well.\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Fade Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade-out, Speed controlled by channel 8\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade-in, Speed controlled by channel 8\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade-In-Out, Speed controlled by channel 8\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Effect, Speed controlled by channel 8\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"4 color Chase Effect, Speed controlled by channel 8\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"12 color Chase Effect, Speed controlled by channel 8\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Controlled by microphone\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Effect\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Effect Speed\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Pattern\",\n        \"Strobe Speed\",\n        \"Fade Control\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/hz-200-compact-hazer.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hz-200 Compact Hazer\",\n  \"shortName\": \"Hz-200\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"Paul Rogalski\"],\n    \"createDate\": \"2024-10-01\",\n    \"lastModifyDate\": \"2024-10-01\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/326263_c_326263_v7_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_hz_200_compact_hazer_dmx.htm\"\n    ],\n    \"video\": [\n      \"https://www.thomann.de/intl/thomanntv_video_stairville_hz_200_compact_hazer_dmx_2428.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [280, 242, 380],\n    \"weight\": 7.5,\n    \"power\": 600,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Haze\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Haze\",\n        \"fogOutputStart\": \"weak\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    },\n    \"Fan Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Haze\",\n        \"Fan Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/led-bar-240-8.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Bar 240/8\",\n  \"shortName\": \"StairvilleLedBar240/8\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"kiki\"],\n    \"createDate\": \"2019-05-14\",\n    \"lastModifyDate\": \"2022-06-10\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/294835_c_294835_v3_r3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_led_bar_2408_rgb_dmx_30.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=n5rRgpYDY7M\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1064, 65, 88],\n    \"weight\": 2.6,\n    \"power\": 36,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"240× 10mm LEDs (96× red, 72× green, 72× blue)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    },\n    \"matrixPixels\": {\n      \"dimensions\": [125, 60, 0],\n      \"spacing\": [0, 0, 0]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [8, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blackout\",\n          \"colors\": [\"#000000\"],\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pattern red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pattern yellow\",\n          \"colors\": [\"#ffff00\"],\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pattern green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pattern cyan\",\n          \"colors\": [\"#00ffff\"],\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pattern blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pattern magenta\",\n          \"colors\": [\"#ff00ff\"],\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pattern white\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed shows\",\n          \"helpWanted\": \"Which shows can be selected at which DMX values?\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Show Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled shows\",\n          \"soundControlled\": true,\n          \"helpWanted\": \"Which shows can be selected at which DMX values?\",\n          \"switchChannels\": {\n            \"Show Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Show Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 2],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [3, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Programs\",\n        \"Show Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"24-channel\",\n      \"shortName\": \"24ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/led-flood-panel-150.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Flood Panel 150\",\n  \"shortName\": \"StairvilleFloodPanel150\",\n  \"categories\": [\"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-03-10\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\"https://images.thomann.de/pics/prod/253358_manual_en.pdf\"],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_led_flood_panel_150_20.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ntFuKR7bSfw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 210, 68],\n    \"weight\": 1.8,\n    \"power\": 20,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"48 red, 51 green and 51 blue 10mm LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [20, 20]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 8],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [9, 17],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff3200\"],\n          \"comment\": \"Red: 255, Green: 50\"\n        },\n        {\n          \"dmxRange\": [18, 26],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff9600\"],\n          \"comment\": \"Red: 255, Green: 150\"\n        },\n        {\n          \"dmxRange\": [27, 35],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [36, 44],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#c8ff00\"],\n          \"comment\": \"Red: 200, Green: 255\"\n        },\n        {\n          \"dmxRange\": [45, 53],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#64ff00\"],\n          \"comment\": \"Red: 100, Green: 255\"\n        },\n        {\n          \"dmxRange\": [54, 62],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#28ff00\"],\n          \"comment\": \"Red: 40, Green: 255\"\n        },\n        {\n          \"dmxRange\": [63, 71],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [72, 80],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff32\"],\n          \"comment\": \"Green: 255, Blue: 50\"\n        },\n        {\n          \"dmxRange\": [81, 89],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff96\"],\n          \"comment\": \"Green: 255, Blue: 150\"\n        },\n        {\n          \"dmxRange\": [90, 98],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [99, 107],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0096ff\"],\n          \"comment\": \"Green: 150, Blue: 255\"\n        },\n        {\n          \"dmxRange\": [108, 116],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0032ff\"],\n          \"comment\": \"Green: 50, Blue: 255\"\n        },\n        {\n          \"dmxRange\": [117, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [126, 134],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#3200ff\"],\n          \"comment\": \"Red: 50, Blue: 255\"\n        },\n        {\n          \"dmxRange\": [135, 143],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#9600ff\"],\n          \"comment\": \"Red: 150, Blue: 255\"\n        },\n        {\n          \"dmxRange\": [144, 152],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [153, 161],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dc00ff\"],\n          \"comment\": \"Red: 220, Blue: 255\"\n        },\n        {\n          \"dmxRange\": [162, 170],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#963264\"],\n          \"comment\": \"Red: 150, Green: 50, Blue: 100\"\n        },\n        {\n          \"dmxRange\": [171, 179],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#32b4dc\"],\n          \"comment\": \"Red: 50, Green: 180, Blue: 220\"\n        },\n        {\n          \"dmxRange\": [180, 188],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#32dc64\"],\n          \"comment\": \"Red: 50, Green: 220, Blue: 100\"\n        },\n        {\n          \"dmxRange\": [189, 197],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#96dc00\"],\n          \"comment\": \"Red: 150, Green: 220\"\n        },\n        {\n          \"dmxRange\": [198, 206],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#9600dc\"],\n          \"comment\": \"Red: 150, Blue: 220\"\n        },\n        {\n          \"dmxRange\": [207, 215],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00b4dc\"],\n          \"comment\": \"Green: 180, Blue: 220\"\n        },\n        {\n          \"dmxRange\": [216, 224],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00dc32\"],\n          \"comment\": \"Green: 220, Blue: 50\"\n        },\n        {\n          \"dmxRange\": [225, 233],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dc6432\"],\n          \"comment\": \"Red: 220, Green: 100, Blue: 50\"\n        },\n        {\n          \"dmxRange\": [234, 242],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#dcc864\"],\n          \"comment\": \"Red: 220, Green: 200, Blue: 100\"\n        },\n        {\n          \"dmxRange\": [243, 251],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffc896\"],\n          \"comment\": \"Red: 255, Green: 200, Blue: 150\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Internal Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Red\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 24],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color presets\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 49],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7-color\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 74],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"3-color\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 99],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7-color\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 124],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3-color\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [125, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fantasy change 1\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 174],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fantasy change 2\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [175, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Red fading\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 224],\n          \"type\": \"Effect\",\n          \"effectName\": \"Green fading\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Blue fading\",\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Red / Color Presets / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"ID Select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"All IDs (1-66)\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 13\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 14\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 15\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 16\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 17\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 18\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 19\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 20\"\n        },\n        {\n          \"dmxRange\": [210, 210],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 21\"\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 22\"\n        },\n        {\n          \"dmxRange\": [212, 212],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 23\"\n        },\n        {\n          \"dmxRange\": [213, 213],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 24\"\n        },\n        {\n          \"dmxRange\": [214, 214],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 25\"\n        },\n        {\n          \"dmxRange\": [215, 215],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 26\"\n        },\n        {\n          \"dmxRange\": [216, 216],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 27\"\n        },\n        {\n          \"dmxRange\": [217, 217],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 28\"\n        },\n        {\n          \"dmxRange\": [218, 218],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 29\"\n        },\n        {\n          \"dmxRange\": [219, 219],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 30\"\n        },\n        {\n          \"dmxRange\": [220, 220],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 31\"\n        },\n        {\n          \"dmxRange\": [221, 221],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 32\"\n        },\n        {\n          \"dmxRange\": [222, 222],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 33\"\n        },\n        {\n          \"dmxRange\": [223, 223],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 34\"\n        },\n        {\n          \"dmxRange\": [224, 224],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 35\"\n        },\n        {\n          \"dmxRange\": [225, 225],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 36\"\n        },\n        {\n          \"dmxRange\": [226, 226],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 37\"\n        },\n        {\n          \"dmxRange\": [227, 227],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 38\"\n        },\n        {\n          \"dmxRange\": [228, 228],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 39\"\n        },\n        {\n          \"dmxRange\": [229, 229],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 40\"\n        },\n        {\n          \"dmxRange\": [230, 230],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 41\"\n        },\n        {\n          \"dmxRange\": [231, 231],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 42\"\n        },\n        {\n          \"dmxRange\": [232, 232],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 43\"\n        },\n        {\n          \"dmxRange\": [233, 233],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 44\"\n        },\n        {\n          \"dmxRange\": [234, 234],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 45\"\n        },\n        {\n          \"dmxRange\": [235, 235],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 46\"\n        },\n        {\n          \"dmxRange\": [236, 236],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 47\"\n        },\n        {\n          \"dmxRange\": [237, 237],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 48\"\n        },\n        {\n          \"dmxRange\": [238, 238],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 49\"\n        },\n        {\n          \"dmxRange\": [239, 239],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 50\"\n        },\n        {\n          \"dmxRange\": [240, 240],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 51\"\n        },\n        {\n          \"dmxRange\": [241, 241],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 52\"\n        },\n        {\n          \"dmxRange\": [242, 242],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 53\"\n        },\n        {\n          \"dmxRange\": [243, 243],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 54\"\n        },\n        {\n          \"dmxRange\": [244, 244],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 55\"\n        },\n        {\n          \"dmxRange\": [245, 245],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 56\"\n        },\n        {\n          \"dmxRange\": [246, 246],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 57\"\n        },\n        {\n          \"dmxRange\": [247, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 58\"\n        },\n        {\n          \"dmxRange\": [248, 248],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 59\"\n        },\n        {\n          \"dmxRange\": [249, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 60\"\n        },\n        {\n          \"dmxRange\": [250, 250],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 61\"\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 62\"\n        },\n        {\n          \"dmxRange\": [252, 252],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 63\"\n        },\n        {\n          \"dmxRange\": [253, 253],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 64\"\n        },\n        {\n          \"dmxRange\": [254, 254],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 65\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"ID 66\"\n        }\n      ]\n    },\n    \"Dimmer Delay\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 250],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Instant\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Delayed\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red / Color Presets / Program Speed / Sound Sensitivity\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Internal Programs\",\n        \"ID Select\",\n        \"Dimmer Delay\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/led-par-56.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR 56\",\n  \"shortName\": \"StairvilleLedPar56\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2021-03-19\",\n    \"lastModifyDate\": \"2021-03-19\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/115012_c_115012_115025_215918_115048_215926_115050_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_led_par_56_10_mm_black_rgb.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [225, 270, 190],\n    \"weight\": 1.2,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"151× 10mm LEDs (50× red, 50× green, 51× blue)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade out\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade in\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade in/out\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mix\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"3-color chases\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"7-color chases\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-to-light\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Strobe\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Macro\",\n        \"Speed / Strobe\",\n        \"Mode\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/led-par-64.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED PAR 64\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Jászberényi Szabolcs\", \"Jakob\"],\n    \"createDate\": \"2021-10-04\",\n    \"lastModifyDate\": \"2021-10-04\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2021-10-04\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.3 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/115048_c_115012_115025_215918_115048_215926_115050_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_led_par_64_10_mm_black_rgb.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [275, 395, 200],\n    \"weight\": 1.7,\n    \"power\": 17,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"183× 10mm LEDs (61× red, 61× green, 61× blue)\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Macro\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Off\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade out\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade in\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Fade in/out\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto mix\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"3-color chases\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"7-color chases\",\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-to-light\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed / Strobe\": \"Strobe\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Macro\",\n        \"Speed / Strobe\",\n        \"Mode\",\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/matrixx-sc-100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"maTrixx SC-100\",\n  \"shortName\": \"SC100\",\n  \"categories\": [\"Scanner\"],\n  \"meta\": {\n    \"authors\": [\"PLANET_XYZ\", \"JonahKr\"],\n    \"createDate\": \"2022-03-07\",\n    \"lastModifyDate\": \"2022-03-07\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.thomann.de/pics/atg/atgdata/document/manual/119950_c_119950_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_matrixx_sc100_dmx_led_effect.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=h0Ih3R4Rldc\"\n    ]\n  },\n  \"physical\": {\n    \"DMXconnector\": \"3-pin\",\n    \"dimensions\": [145, 165, 425],\n    \"power\": 40,\n    \"weight\": 3.1,\n    \"bulb\": {\n      \"type\": \"LED matrix (16× red, 12× green, 12× blue, 12× white)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [21, 21]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"90deg\"\n      }\n    },\n    \"Patterns / Shows\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\",\n          \"comment\": \"Blackout\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 1\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 13\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 14\"\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pattern 15\"\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 1\"\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 2\"\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 3\"\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 4\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 5\"\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 6\"\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 7\"\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 8\"\n        },\n        {\n          \"dmxRange\": [240, 249],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 9\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Show 10\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [10, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"DMX\",\n      \"shortName\": \"DMX\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Patterns / Shows\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/mh-100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MH-100\",\n  \"shortName\": \"svlmh100\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2017-10-28\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\"https://images.thomann.de/pics/atg/atgdata/document/manual/c_325876_en_online.pdf\"],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_mh_100_beam_36x3w_led.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=fasqGFMdPOU\",\n      \"https://www.youtube.com/watch?v=Qk0iHZVd5-s\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [260, 310, 148],\n    \"weight\": 4.9,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"36 × 3 W LEDs (8 × red, 10 × green, 10 × blue, 8 × white)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [8, 8]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"630deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"220deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 35],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [36, 55],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [56, 75],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3400K\"\n        },\n        {\n          \"dmxRange\": [76, 95],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4200K\"\n        },\n        {\n          \"dmxRange\": [96, 115],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4900K\"\n        },\n        {\n          \"dmxRange\": [116, 135],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5600K\"\n        },\n        {\n          \"dmxRange\": [136, 175],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [176, 195],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [196, 215],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8000K\"\n        },\n        {\n          \"dmxRange\": [216, 235],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8500K\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"10000K\"\n        }\n      ]\n    },\n    \"Constant Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [15, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"One of 28 preprogrammed colors\",\n          \"helpWanted\": \"Which 28 preprogrammed colors?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 19],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [20, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 199],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound control\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"5s\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-Channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"14-Channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Temperature\",\n        \"Constant Color\",\n        \"Strobe\",\n        \"Special Functions\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/mh-x20.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MH-X20\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Kristo\", \"Paul Rogalski\"],\n    \"createDate\": \"2024-10-01\",\n    \"lastModifyDate\": \"2024-10-01\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2024-10-01\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.3 GIT)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\"https://images.thomann.de/pics/atg/atgdata/document/manual/c_299888_en_online.pdf\"]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 290, 210],\n    \"weight\": 4.2,\n    \"power\": 40,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"lumens\": 9800\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff557f\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00aa00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#55ffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff5500\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/aliases/qlcplus/Chauvet/gobo00045.svg\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/aliases/qlcplus/Chauvet/gobo00046.png\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/aliases/qlcplus/Chauvet/gobo00048.svg\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/aliases/qlcplus/Chauvet/gobo00049.svg\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/aliases/qlcplus/Chauvet/gobo00050.png\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/aliases/qlcplus/Chauvet/gobo00052.svg\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/aliases/qlcplus/Chauvet/gobo00053.svg\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan Fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt Fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Color Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Gobo\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Special functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 27],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [28, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [48, 67],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt or Gobo wheel movement\"\n        },\n        {\n          \"dmxRange\": [68, 87],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Color wheel movement\"\n        },\n        {\n          \"dmxRange\": [88, 107],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt or Color wheel movement\"\n        },\n        {\n          \"dmxRange\": [108, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Gobo or Color wheel movement\"\n        },\n        {\n          \"dmxRange\": [128, 147],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt, Gobo or Color wheel movement\"\n        },\n        {\n          \"dmxRange\": [148, 167],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Pan\"\n        },\n        {\n          \"dmxRange\": [168, 187],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Tilt\"\n        },\n        {\n          \"dmxRange\": [188, 207],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Color wheel\"\n        },\n        {\n          \"dmxRange\": [208, 227],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset Gobo wheel\"\n        },\n        {\n          \"dmxRange\": [228, 247],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all channels\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Gobo\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan Fine\",\n        \"Tilt Fine\",\n        \"Pan/Tilt Speed\",\n        \"Color\",\n        \"Shutter / Strobe\",\n        \"Dimmer\",\n        \"Gobo\",\n        \"Special functions\",\n        \"Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/mh-x25.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MH-X25\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"p_0g_8mm3_\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-01-30\",\n    \"lastModifyDate\": \"2018-09-04\"\n  },\n  \"links\": {\n    \"manual\": [\"https://images.thomann.de/pics/prod/c_238185_en_online.pdf\"],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=QmIARRiHV48\",\n      \"https://www.youtube.com/watch?v=ecWyJqRIWAs\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [240, 370, 280],\n    \"weight\": 10.3,\n    \"power\": 102,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4x LED (all white)\"\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Peachblow\",\n          \"colors\": [\"#d7735b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\",\n          \"colors\": [\"#add8e6\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow-Green\",\n          \"colors\": [\"#ccfe50\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 2\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 3\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 4\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 5\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 6\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 7\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"name\": \"Gobo 8\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": \"50%\",\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [45, 54],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 2\n        },\n        {\n          \"dmxRange\": [55, 64],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 2,\n          \"slotNumberEnd\": 3\n        },\n        {\n          \"dmxRange\": [65, 73],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 3,\n          \"slotNumberEnd\": 4\n        },\n        {\n          \"dmxRange\": [74, 83],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 4,\n          \"slotNumberEnd\": 5\n        },\n        {\n          \"dmxRange\": [84, 92],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 5,\n          \"slotNumberEnd\": 6\n        },\n        {\n          \"dmxRange\": [93, 101],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 6,\n          \"slotNumberEnd\": 7\n        },\n        {\n          \"dmxRange\": [102, 110],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 7,\n          \"slotNumberEnd\": 8\n        },\n        {\n          \"dmxRange\": [111, 119],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 8,\n          \"slotNumberEnd\": 9\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Color Wheel\",\n          \"slotNumberStart\": 9,\n          \"slotNumberEnd\": 10\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow reverse\",\n          \"speedEnd\": \"fast reverse\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Gobo\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Gobo Wheel\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [64, 147],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [148, 231],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Yo-yo effect\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Special functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while pan / tilt change\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No Blackout while move\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while color change\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No Blackout while color change\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while gobo change\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No Blackout while gobo change\"\n        },\n        {\n          \"dmxRange\": [56, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during movement\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan and tilt\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset color wheel\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo wheel\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo rotation\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all channels\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [136, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [151, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [166, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [181, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [196, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [211, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [226, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color\",\n        \"Shutter\",\n        \"Gobo\",\n        \"Gobo rotation\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Color\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Gobo\",\n        \"Gobo rotation\",\n        \"Special functions\",\n        \"Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/mh-x30-led-spot.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MH-x30 LED Spot\",\n  \"shortName\": \"StairvilleMHx30Spot\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Voyo\", \"Ryan Goodwin\"],\n    \"createDate\": \"2019-07-22\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.thomann.de/pics/atg/atgdata/document/manual/398853_c_398853_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_mh_x30_led_spot_moving_head.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i5728p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [280, 374, 150],\n    \"weight\": 5.8,\n    \"power\": 94,\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"30W white LED\",\n      \"colorTemperature\": 6000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14, 14]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light blue\",\n          \"colors\": [\"#00ccff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light yellow\",\n          \"colors\": [\"#ffff99\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"200deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 128],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [129, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [96, 107],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [108, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [120, 131],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [132, 143],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [144, 155],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [156, 167],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [168, 179],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 11],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [12, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [24, 35],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [36, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [48, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [60, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [72, 83],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [84, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [96, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [108, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 131],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [132, 143],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [144, 155],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [156, 167],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [168, 179],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [180, 191],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"360deg\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Maintenance\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\",\n          \"hold\": \"5s\"\n        },\n        {\n          \"dmxRange\": [21, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Focus\"\n      ]\n    },\n    {\n      \"name\": \"12-channel\",\n      \"shortName\": \"12ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Focus\",\n        \"Maintenance\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/mh-x30.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\",\n  \"name\": \"MH-x30\",\n  \"redirectTo\": \"stairville/mh-x30-led-spot\",\n  \"reason\": \"FixtureRenamed\"\n}\n"
  },
  {
    "path": "fixtures/stairville/mh-x50.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MH-X50+\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\"],\n    \"createDate\": \"2020-07-16\",\n    \"lastModifyDate\": \"2020-07-20\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/250558_c_250558_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_mhx50_led_spot_moving_head.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de//vidiot/02591c1c/video_i2514p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [240, 370, 280],\n    \"weight\": 10.3,\n    \"power\": 135,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"50W LED\",\n      \"lumens\": 940\n    },\n    \"lens\": {\n      \"degreesMinMax\": [14, 14]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Peachblow\",\n          \"colors\": [\"#d7735b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#00aeff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Kelly-Green\",\n          \"colors\": [\"#4cbb17\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Orange\",\n          \"colors\": [\"#ffb300\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark blue\",\n          \"colors\": [\"#1e00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/10-circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/glass-raindrops-on-window\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/3-fold-swirl\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/biohazard\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/rose-petal\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/triangle-hexagon-pattern\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/dot-spiral\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [64, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [71, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [78, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [85, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [92, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [99, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [106, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [113, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"13Hz\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [64, 147],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [148, 231],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"isShaking\": \"slot\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 247],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Pan and Tilt\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout while Pan and Tilt\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while changing color\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout while changing color\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while changing gobo\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout while changing gobo\"\n        },\n        {\n          \"dmxRange\": [56, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset tilt\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset color wheel\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo wheel\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo rotation\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset prism\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset focus\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all channels\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Built-in Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Shutter\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism\",\n        \"Focus\"\n      ]\n    },\n    {\n      \"name\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Speed\",\n        \"Color Wheel\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Special Functions\",\n        \"Built-in Programs\",\n        \"Prism\",\n        \"Focus\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/mh-x60.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"MH-X60\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\", \"Ryan Goodwin\"],\n    \"createDate\": \"2021-07-17\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/322408_c_322408_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_mh_x60_led_spot_moving_head.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i2654p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [325, 290, 435],\n    \"weight\": 10.4,\n    \"power\": 170,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input only\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"60W LED\",\n      \"lumens\": 1010\n    },\n    \"lens\": {\n      \"degreesMinMax\": [13, 13]\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Color\",\n          \"name\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Peachblow\",\n          \"colors\": [\"#d7735b\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#00aeff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Kelly-Green\",\n          \"colors\": [\"#4cbb17\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Orange\",\n          \"colors\": [\"#ffb300\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark blue\",\n          \"colors\": [\"#1e00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/10-circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/glass-raindrops-on-window\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/3-fold-swirl\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/biohazard\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/rose-petal\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/triangle-hexagon-pattern\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/dot-spiral\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 6],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [7, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [14, 20],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [21, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [28, 34],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [35, 41],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [42, 48],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [49, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9\n        },\n        {\n          \"dmxRange\": [64, 70],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [71, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [78, 84],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [85, 91],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [92, 98],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [99, 105],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [106, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [113, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 9.5\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Shutter\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 215],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"13Hz\"\n        },\n        {\n          \"dmxRange\": [216, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [64, 147],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [148, 231],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Gobo Wheel\",\n          \"isShaking\": \"slot\"\n        }\n      ]\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 247],\n          \"type\": \"Prism\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Prism\",\n          \"speed\": \"stop\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"far\",\n        \"distanceEnd\": \"near\"\n      }\n    },\n    \"Speed\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Special Functions\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while Pan and Tilt\"\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout while Pan and Tilt\"\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while changing color\"\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout while changing color\"\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while changing gobo\"\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"Maintenance\",\n          \"comment\": \"No blackout while changing gobo\"\n        },\n        {\n          \"dmxRange\": [56, 87],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout while moving\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset pan\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset tilt\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset color wheel\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo wheel\"\n        },\n        {\n          \"dmxRange\": [128, 135],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset gobo rotation\"\n        },\n        {\n          \"dmxRange\": [136, 143],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset prism\"\n        },\n        {\n          \"dmxRange\": [144, 151],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset focus\"\n        },\n        {\n          \"dmxRange\": [152, 159],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset all channels\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Built-in Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\"\n        },\n        {\n          \"dmxRange\": [24, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\"\n        },\n        {\n          \"dmxRange\": [40, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\"\n        },\n        {\n          \"dmxRange\": [56, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\"\n        },\n        {\n          \"dmxRange\": [72, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\"\n        },\n        {\n          \"dmxRange\": [88, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\"\n        },\n        {\n          \"dmxRange\": [104, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\"\n        },\n        {\n          \"dmxRange\": [120, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\"\n        },\n        {\n          \"dmxRange\": [136, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [152, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [168, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [184, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [200, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [232, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music controlled 8\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Shutter\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Prism\",\n        \"Focus\"\n      ]\n    },\n    {\n      \"name\": \"14ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Pan fine\",\n        \"Tilt fine\",\n        \"Speed\",\n        \"Color Wheel\",\n        \"Shutter\",\n        \"Dimmer\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Special Functions\",\n        \"Built-in Programs\",\n        \"Prism\",\n        \"Focus\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/octagon-theater-20x6w-cw-ww-a.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Octagon Theater 20x6W CW/WW/A\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"SK\", \"Felix Edelmann\"],\n    \"createDate\": \"2019-06-08\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/367135_c_367135_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_octagon_theater_20x6w_cw_ww_a.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=c_UDU4X6i6c\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [295, 340, 200],\n    \"weight\": 6.9,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"20x 6W CW/WW/A LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [36, 36]\n    }\n  },\n  \"availableChannels\": {\n    \"IntensityColdWhite\": {\n      \"name\": \"Cold White\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cold White\"\n      }\n    },\n    \"SoundControlColdWhite\": {\n      \"name\": \"Sound Control\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound Control\",\n        \"soundControlled\": true,\n        \"helpWanted\": \"What does this channel do? Isn't sound control already activated from 'Programs Cold White' channel?\"\n      }\n    },\n    \"SoundControl2ColdWhite\": {\n      \"name\": \"Sound Control Mode 2\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound Control Mode 2\",\n        \"soundControlled\": true,\n        \"helpWanted\": \"What does this channel do? Isn't sound control mode 2 already activated from Programs channel?\"\n      }\n    },\n    \"ProgramSelColdWhite\": {\n      \"name\": \"Program Selection\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Program Selection\",\n        \"helpWanted\": \"Can one select individual programs per color? If so, at which DMX value can which programs be selected?\"\n      }\n    },\n    \"FadeSpeedColdWhite\": {\n      \"name\": \"Fade Speed\",\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"StrobeColdWhite\": {\n      \"name\": \"Strobe Intensity\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cold White\",\n        \"helpWanted\": \"How does this channel differ from normal 'Cold White Intensity'?\"\n      }\n    },\n    \"ProgramsColdWhite\": {\n      \"name\": \"Programs Cold White\",\n      \"defaultValue\": 31,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Cold White Intensity / Sound Control\": \"NoFunction1\",\n            \"Cold White Fade Speed / Strobe Intensity\": \"NoFunction2\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity\",\n          \"helpWanted\": \"Does this capability directly control Cold White intensity or only activate the Intensity channel?\",\n          \"switchChannels\": {\n            \"Cold White Intensity / Sound Control\": \"IntensityColdWhite\",\n            \"Cold White Fade Speed / Strobe Intensity\": \"NoFunction2\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Cold White Intensity / Sound Control\": \"SoundControlColdWhite\",\n            \"Cold White Fade Speed / Strobe Intensity\": \"NoFunction2\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 150],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Cold White Intensity / Sound Control\": \"NoFunction1\",\n            \"Cold White Fade Speed / Strobe Intensity\": \"FadeSpeedColdWhite\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Cold White Intensity / Sound Control\": \"NoFunction1\",\n            \"Cold White Fade Speed / Strobe Intensity\": \"FadeSpeedColdWhite\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 230],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"switchChannels\": {\n            \"Cold White Intensity / Sound Control\": \"NoFunction1\",\n            \"Cold White Fade Speed / Strobe Intensity\": \"FadeSpeedColdWhite\"\n          }\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"switchChannels\": {\n            \"Cold White Intensity / Sound Control\": \"IntensityColdWhite\",\n            \"Cold White Fade Speed / Strobe Intensity\": \"StrobeColdWhite\"\n          }\n        }\n      ]\n    },\n    \"IntensityWarmWhite\": {\n      \"name\": \"Warm White\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"SoundControlWarmWhite\": {\n      \"name\": \"Sound Control\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound Control\",\n        \"soundControlled\": true,\n        \"helpWanted\": \"What does this channel do? Isn't sound control already activated from 'Programs Warm White' channel?\"\n      }\n    },\n    \"SoundControl2WarmWhite\": {\n      \"name\": \"Sound Control Mode 2\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound Control Mode 2\",\n        \"soundControlled\": true,\n        \"helpWanted\": \"What does this channel do? Isn't sound control mode 2 already activated from Programs channel?\"\n      }\n    },\n    \"ProgramSelWarmWhite\": {\n      \"name\": \"Program Selection\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Program Selection\",\n        \"helpWanted\": \"Can one select individual programs per color? If so, at which DMX value can which programs be selected?\"\n      }\n    },\n    \"FadeSpeedWarmWhite\": {\n      \"name\": \"Fade Speed\",\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"StrobeWarmWhite\": {\n      \"name\": \"Strobe Intensity\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\",\n        \"helpWanted\": \"How does this channel differ from normal 'Warm White Intensity'?\"\n      }\n    },\n    \"ProgramsWarmWhite\": {\n      \"name\": \"Programs Warm White\",\n      \"defaultValue\": 31,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Warm White Intensity / Sound Control\": \"NoFunction3\",\n            \"Warm White Fade Speed / Strobe Intensity\": \"NoFunction4\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity\",\n          \"helpWanted\": \"Does this capability directly control Warm White intensity or only activate the Intensity channel?\",\n          \"switchChannels\": {\n            \"Warm White Intensity / Sound Control\": \"IntensityWarmWhite\",\n            \"Warm White Fade Speed / Strobe Intensity\": \"NoFunction4\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Warm White Intensity / Sound Control\": \"SoundControlWarmWhite\",\n            \"Warm White Fade Speed / Strobe Intensity\": \"NoFunction4\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 150],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Warm White Intensity / Sound Control\": \"NoFunction3\",\n            \"Warm White Fade Speed / Strobe Intensity\": \"FadeSpeedWarmWhite\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Warm White Intensity / Sound Control\": \"NoFunction3\",\n            \"Warm White Fade Speed / Strobe Intensity\": \"FadeSpeedWarmWhite\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 230],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"switchChannels\": {\n            \"Warm White Intensity / Sound Control\": \"NoFunction3\",\n            \"Warm White Fade Speed / Strobe Intensity\": \"FadeSpeedWarmWhite\"\n          }\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"switchChannels\": {\n            \"Warm White Intensity / Sound Control\": \"IntensityWarmWhite\",\n            \"Warm White Fade Speed / Strobe Intensity\": \"StrobeWarmWhite\"\n          }\n        }\n      ]\n    },\n    \"IntensityAmber\": {\n      \"name\": \"Amber\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"SoundControlAmber\": {\n      \"name\": \"Sound Control\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound Control\",\n        \"soundControlled\": true,\n        \"helpWanted\": \"What does this channel do? Isn't sound control already activated from 'Programs Amber' channel?\"\n      }\n    },\n    \"SoundControl2Amber\": {\n      \"name\": \"Sound Control Mode 2\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound Control Mode 2\",\n        \"soundControlled\": true,\n        \"helpWanted\": \"What does this channel do? Isn't sound control mode 2 already activated from Programs channel?\"\n      }\n    },\n    \"ProgramSelAmber\": {\n      \"name\": \"Program Selection\",\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Program Selection\",\n        \"helpWanted\": \"Can one select individual programs per color? If so, at which DMX value can which programs be selected?\"\n      }\n    },\n    \"FadeSpeedAmber\": {\n      \"name\": \"Fade Speed\",\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"StrobeAmber\": {\n      \"name\": \"Strobe Intensity\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\",\n        \"helpWanted\": \"How does this channel differ from normal 'Amber Intensity'?\"\n      }\n    },\n    \"ProgramsAmber\": {\n      \"name\": \"Programs Amber\",\n      \"defaultValue\": 31,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Amber Intensity / Sound Control\": \"NoFunction5\",\n            \"Amber Fade Speed / Strobe Intensity\": \"NoFunction6\"\n          }\n        },\n        {\n          \"dmxRange\": [31, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Intensity\",\n          \"helpWanted\": \"Does this capability directly control Amber intensity or only activate the Intensity channel?\",\n          \"switchChannels\": {\n            \"Amber Intensity / Sound Control\": \"IntensityAmber\",\n            \"Amber Fade Speed / Strobe Intensity\": \"NoFunction6\"\n          }\n        },\n        {\n          \"dmxRange\": [71, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Amber Intensity / Sound Control\": \"SoundControlAmber\",\n            \"Amber Fade Speed / Strobe Intensity\": \"NoFunction6\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 150],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Amber Intensity / Sound Control\": \"NoFunction5\",\n            \"Amber Fade Speed / Strobe Intensity\": \"FadeSpeedAmber\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 190],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Amber Intensity / Sound Control\": \"NoFunction5\",\n            \"Amber Fade Speed / Strobe Intensity\": \"FadeSpeedAmber\"\n          }\n        },\n        {\n          \"dmxRange\": [191, 230],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"switchChannels\": {\n            \"Amber Intensity / Sound Control\": \"NoFunction5\",\n            \"Amber Fade Speed / Strobe Intensity\": \"FadeSpeedAmber\"\n          }\n        },\n        {\n          \"dmxRange\": [231, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"switchChannels\": {\n            \"Amber Intensity / Sound Control\": \"IntensityAmber\",\n            \"Amber Fade Speed / Strobe Intensity\": \"StrobeAmber\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"comment\": \"Program / Fade speed\"\n      }\n    },\n    \"Strobe Speed\": {\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Hue\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Fade / Program color hue\"\n      }\n    },\n    \"Sound Control Mode 1\": {\n      \"capability\": {\n        \"type\": \"Effect\",\n        \"effectName\": \"Sound Control Mode 1\",\n        \"soundControlled\": true,\n        \"helpWanted\": \"What does this channel do? Isn't sound control mode 1 already activated from Programs channel?\"\n      }\n    },\n    \"Programs\": {\n      \"defaultValue\": 11,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Warm White\": \"NoFunction1\",\n            \"Cold White\": \"NoFunction2\",\n            \"Amber\": \"NoFunction3\",\n            \"Speed\": \"NoFunction4\",\n            \"Sound Control Mode 1 / Hue\": \"NoFunction5\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 50],\n          \"type\": \"Intensity\",\n          \"helpWanted\": \"Does this also control general intensity or only activate the color intensity channels?\",\n          \"switchChannels\": {\n            \"Warm White\": \"IntensityWarmWhite\",\n            \"Cold White\": \"IntensityColdWhite\",\n            \"Amber\": \"IntensityAmber\",\n            \"Speed\": \"Program Speed\",\n            \"Sound Control Mode 1 / Hue\": \"Sound Control Mode 1\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control mode 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Warm White\": \"NoFunction1\",\n            \"Cold White\": \"NoFunction2\",\n            \"Amber\": \"NoFunction3\",\n            \"Speed\": \"NoFunction4\",\n            \"Sound Control Mode 1 / Hue\": \"Sound Control Mode 1\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control mode 2\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Warm White\": \"SoundControl2WarmWhite\",\n            \"Cold White\": \"SoundControl2ColdWhite\",\n            \"Amber\": \"SoundControl2Amber\",\n            \"Speed\": \"NoFunction4\",\n            \"Sound Control Mode 1 / Hue\": \"NoFunction5\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 170],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Warm White\": \"NoFunction1\",\n            \"Cold White\": \"NoFunction2\",\n            \"Amber\": \"NoFunction3\",\n            \"Speed\": \"Program Speed\",\n            \"Sound Control Mode 1 / Hue\": \"Hue\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program selection\",\n          \"helpWanted\": \"At which DMX value can which program be selected?\",\n          \"switchChannels\": {\n            \"Warm White\": \"ProgramSelWarmWhite\",\n            \"Cold White\": \"ProgramSelColdWhite\",\n            \"Amber\": \"ProgramSelAmber\",\n            \"Speed\": \"Program Speed\",\n            \"Sound Control Mode 1 / Hue\": \"Hue\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"switchChannels\": {\n            \"Warm White\": \"StrobeWarmWhite\",\n            \"Cold White\": \"StrobeColdWhite\",\n            \"Amber\": \"StrobeAmber\",\n            \"Speed\": \"Strobe Speed\",\n            \"Sound Control Mode 1 / Hue\": \"NoFunction5\"\n          }\n        }\n      ]\n    },\n    \"NoFunction1\": {\n      \"name\": \"No Function\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunction2\": {\n      \"name\": \"No Function\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunction3\": {\n      \"name\": \"No Function\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunction4\": {\n      \"name\": \"No Function\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunction5\": {\n      \"name\": \"No Function\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunction6\": {\n      \"name\": \"No Function\",\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-Channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"IntensityColdWhite\",\n        \"IntensityWarmWhite\",\n        \"IntensityAmber\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"6-Channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Cold White\",\n        \"Warm White\",\n        \"Amber\",\n        \"Speed\",\n        \"Sound Control Mode 1 / Hue\",\n        \"Programs\"\n      ]\n    },\n    {\n      \"name\": \"9-Channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Cold White Intensity / Sound Control\",\n        \"Cold White Fade Speed / Strobe Intensity\",\n        \"ProgramsColdWhite\",\n        \"Warm White Intensity / Sound Control\",\n        \"Warm White Fade Speed / Strobe Intensity\",\n        \"ProgramsWarmWhite\",\n        \"Amber Intensity / Sound Control\",\n        \"Amber Fade Speed / Strobe Intensity\",\n        \"ProgramsAmber\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/par-56.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"PAR 56\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Moritz A. Vieli\"],\n    \"createDate\": \"2019-10-30\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.thomann.de/pics/atg/atgdata/document/manual/c_193245_v2_r3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_led_par_56_alu_schwarz.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de//vidiot/02591c1c/video_i2192p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [295, 225, 225],\n    \"weight\": 1.4,\n    \"power\": 16,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\",\n          \"comment\": \"RGB Control\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"7 color fades\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 color changes\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3 color changes\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Effect Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 100],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [151, 255],\n          \"type\": \"EffectSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Speed control by the device\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Mode\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Effect Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/remus-hexspot-515.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Remus HexSpot 515\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"LGK\", \"Ken Harris\", \"Flo Edelmann\"],\n    \"createDate\": \"2024-03-05\",\n    \"lastModifyDate\": \"2024-03-05\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_531015_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_remus_hexspot_515.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i11407p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [225, 230, 190],\n    \"weight\": 2.5,\n    \"power\": 100,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"RGBWAUV\",\n      \"colorTemperature\": 3500\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"3200K\",\n          \"colorTemperatureEnd\": \"7280K\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"helpWanted\": \"Is this increasing speed, too?\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"The manual lists 0…5 as Blackout and doesn't mention 6…10. Are these distinct capabilities?\"\n        },\n        {\n          \"dmxRange\": [11, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffd000\"],\n          \"comment\": \"Warm yellow\"\n        },\n        {\n          \"dmxRange\": [30, 101],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"What ranges/colors are here?\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffeebe\"],\n          \"comment\": \"Warm white\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ccffff\"],\n          \"comment\": \"Cool white\"\n        },\n        {\n          \"dmxRange\": [126, 127],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 63],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Linear course\"\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Exponential course\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Logarithmic course\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"S-curve shaped course\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Color Macros\",\n        \"Color Temperature\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/revueled-120-cob-rgbww.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RevueLED 120 COB RGBWW\",\n  \"shortName\": \"SVRevue120RGBWW\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"RAZAKANIRINA\", \"pade\", \"Luke Nelson\"],\n    \"createDate\": \"2019-04-15\",\n    \"lastModifyDate\": \"2025-08-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/414200_c_414200_r2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_revueled_120_cob_rgb_ww_dmx.htm\"\n    ],\n    \"video\": [\n      \"https://www.thomann.de/gb/thomanntv_video_stairville_revueled_120_cob_rgb_6191.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [258, 164, 557],\n    \"weight\": 5.5,\n    \"power\": 150,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"120W COB RGBWW LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [50, 50]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Warm White\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0%\",\n          \"speedEnd\": \"100%\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in automatic show programs\",\n          \"helpWanted\": \"What programs are available and at which DMX values?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Warm White\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Auto Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/revueled-120-cob-true-white.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"RevueLED 120 COB True White\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\"],\n    \"createDate\": \"2021-07-17\",\n    \"lastModifyDate\": \"2024-01-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/443734_c_443734_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_revueled_120_cob_true_white.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [440, 250, 160],\n    \"weight\": 5.5,\n    \"power\": 120,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 120W COB CW/WW LED\",\n      \"lumens\": 7000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [50, 50]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Color temperature adjustment (2800K…7800K) follows dimmer value\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperatureStart\": \"2800K\",\n          \"colorTemperatureEnd\": \"7800K\"\n        }\n      ]\n    },\n    \"Intensity Warm White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Warm White\"\n      }\n    },\n    \"Intensity Cold White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Cold White\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 1\",\n      \"shortName\": \"2ch-1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 2\",\n      \"shortName\": \"2ch-2\",\n      \"channels\": [\n        \"Intensity Warm White\",\n        \"Intensity Cold White\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Intensity Warm White\",\n        \"Intensity Cold White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/sonicpulse-led-bar-05.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SonicPulse LED Bar 05\",\n  \"shortName\": \"ledbar05\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2026-01-28\",\n    \"lastModifyDate\": \"2026-01-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/580867_c_580867_580868_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/de/stairville_sonicpulse_led_bar_05.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i11891p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [572, 165, 65],\n    \"weight\": 1.4,\n    \"power\": 29,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 3000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [9, 9]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Segment 1\": [\"1\", \"2\", \"3\"],\n      \"Segment 2\": [\"4\", \"5\", \"6\"],\n      \"Segment 3\": [\"7\", \"8\", \"9\"],\n      \"Segment 4\": [\"10\", \"11\", \"12\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Auto Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Sound Mode\",\n          \"switchChannels\": {\n            \"Effect Parameter\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Automatic Mode\",\n          \"switchChannels\": {\n            \"Effect Parameter\": \"Auto Mode Speed\"\n          }\n        }\n      ]\n    },\n    \"Effect Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 1\"\n        },\n        {\n          \"dmxRange\": [26, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 2\"\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 3\"\n        },\n        {\n          \"dmxRange\": [46, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 4\"\n        },\n        {\n          \"dmxRange\": [56, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 5\"\n        },\n        {\n          \"dmxRange\": [66, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 1\"\n        },\n        {\n          \"dmxRange\": [76, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 2\"\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 3\"\n        },\n        {\n          \"dmxRange\": [96, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 6\"\n        },\n        {\n          \"dmxRange\": [106, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 7\"\n        },\n        {\n          \"dmxRange\": [116, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 8\"\n        },\n        {\n          \"dmxRange\": [126, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 9\"\n        },\n        {\n          \"dmxRange\": [136, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 10\"\n        },\n        {\n          \"dmxRange\": [146, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 11\"\n        },\n        {\n          \"dmxRange\": [156, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 12\"\n        },\n        {\n          \"dmxRange\": [166, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 4\"\n        },\n        {\n          \"dmxRange\": [176, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 5\"\n        },\n        {\n          \"dmxRange\": [186, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 6\"\n        },\n        {\n          \"dmxRange\": [196, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 7\"\n        },\n        {\n          \"dmxRange\": [206, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 8\"\n        },\n        {\n          \"dmxRange\": [216, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 9\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 10\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 11\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Sound Mode Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [26, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [46, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [56, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [66, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [76, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [106, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [116, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [126, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [136, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [146, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [156, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 16\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [166, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 17\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 18\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [186, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 19\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [196, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 20\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [206, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 21\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 22\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 23\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 24\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 25\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Auto Mode Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"RGBW color chasing\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Color Presets\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Generic\",\n          \"comment\": \"Color Macros\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Music Controlled\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 21],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [28, 33],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange Red\",\n          \"colors\": [\"#ff0e00\"]\n        },\n        {\n          \"dmxRange\": [34, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red Orange\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [40, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff7d00\"]\n        },\n        {\n          \"dmxRange\": [46, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [52, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Shining Gold\",\n          \"colors\": [\"#ffd200\"]\n        },\n        {\n          \"dmxRange\": [58, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [64, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Yellow\",\n          \"colors\": [\"#c8ff00\"]\n        },\n        {\n          \"dmxRange\": [70, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime\",\n          \"colors\": [\"#a0ff00\"]\n        },\n        {\n          \"dmxRange\": [76, 81],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chartreuse\",\n          \"colors\": [\"#6eff00\"]\n        },\n        {\n          \"dmxRange\": [82, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Laser Green\",\n          \"colors\": [\"#46ff00\"]\n        },\n        {\n          \"dmxRange\": [88, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [94, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lawn Green\",\n          \"colors\": [\"#00ff0a\"]\n        },\n        {\n          \"dmxRange\": [100, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Forest Green\",\n          \"colors\": [\"#00ff19\"]\n        },\n        {\n          \"dmxRange\": [106, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Green\",\n          \"colors\": [\"#00ff28\"]\n        },\n        {\n          \"dmxRange\": [112, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emerald\",\n          \"colors\": [\"#00ff46\"]\n        },\n        {\n          \"dmxRange\": [118, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#00ff78\"]\n        },\n        {\n          \"dmxRange\": [124, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [130, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Azure\",\n          \"colors\": [\"#0064ff\"]\n        },\n        {\n          \"dmxRange\": [136, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [142, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Water Ocean Blue\",\n          \"colors\": [\"#1400ff\"]\n        },\n        {\n          \"dmxRange\": [148, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Kingfisher Feathers Blue\",\n          \"colors\": [\"#3200ff\"]\n        },\n        {\n          \"dmxRange\": [154, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Crystaline Purple\",\n          \"colors\": [\"#5000ff\"]\n        },\n        {\n          \"dmxRange\": [160, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#8200ff\"]\n        },\n        {\n          \"dmxRange\": [166, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Electric Purple Violet\",\n          \"colors\": [\"#b400ff\"]\n        },\n        {\n          \"dmxRange\": [172, 177],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dragon Fruit Purple\",\n          \"colors\": [\"#e100ff\"]\n        },\n        {\n          \"dmxRange\": [178, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [184, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink Magenta\",\n          \"colors\": [\"#ff00dc\"]\n        },\n        {\n          \"dmxRange\": [190, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose\",\n          \"colors\": [\"#ff0046\"]\n        },\n        {\n          \"dmxRange\": [196, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Morning Sun Red\",\n          \"colors\": [\"#ff0014\"]\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Absolutely Red\",\n          \"colors\": [\"#ff0007\"]\n        },\n        {\n          \"dmxRange\": [208, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [214, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#ff9090\"]\n        },\n        {\n          \"dmxRange\": [220, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter Pink\",\n          \"colors\": [\"#ffc0c0\"]\n        },\n        {\n          \"dmxRange\": [226, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#90ff90\"]\n        },\n        {\n          \"dmxRange\": [232, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter Green\",\n          \"colors\": [\"#c0ffc0\"]\n        },\n        {\n          \"dmxRange\": [238, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#9090ff\"]\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter Blue\",\n          \"colors\": [\"#c0c0ff\"]\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cool White\",\n          \"colors\": [\"#eeeeff\"]\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Auto Mode\",\n        \"Effect Selection\",\n        \"Sound Mode Selection\",\n        \"Effect Parameter\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Mode Selection\",\n        \"Color Presets\",\n        \"Effect Selection\",\n        \"Sound Mode Selection\",\n        \"Effect Speed / Sound Sensitivity\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"23-channel\",\n      \"shortName\": \"23ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Mode Selection\",\n        \"Color Presets\",\n        \"Effect Selection\",\n        \"Sound Mode Selection\",\n        \"Effect Speed / Sound Sensitivity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"Segment 1\",\n            \"Segment 2\",\n            \"Segment 3\",\n            \"Segment 4\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/sonicpulse-led-bar-10.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SonicPulse LED Bar 10\",\n  \"shortName\": \"ledbar10\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Leon Dietrich\", \"Flo Edelmann\"],\n    \"createDate\": \"2026-01-27\",\n    \"lastModifyDate\": \"2026-01-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/580867_c_580867_580868_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/de/stairville_sonicpulse_led_bar_10.htm\"\n    ],\n    \"video\": [\n      \"https://video1.thomann.de/vidiot/02591c1c/video_i11891p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1075, 165, 65],\n    \"weight\": 2.8,\n    \"power\": 31,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\",\n      \"colorTemperature\": 3000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [9, 9]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [24, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Segment 1\": [\"1\", \"2\", \"3\"],\n      \"Segment 2\": [\"4\", \"5\", \"6\"],\n      \"Segment 3\": [\"7\", \"8\", \"9\"],\n      \"Segment 4\": [\"10\", \"11\", \"12\"],\n      \"Segment 5\": [\"13\", \"14\", \"15\"],\n      \"Segment 6\": [\"16\", \"17\", \"18\"],\n      \"Segment 7\": [\"19\", \"20\", \"21\"],\n      \"Segment 8\": [\"22\", \"23\", \"24\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Auto Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Sound Mode\",\n          \"switchChannels\": {\n            \"Effect Parameter\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Automatic Mode\",\n          \"switchChannels\": {\n            \"Effect Parameter\": \"Auto Mode Speed\"\n          }\n        }\n      ]\n    },\n    \"Effect Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 1\"\n        },\n        {\n          \"dmxRange\": [26, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 2\"\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 3\"\n        },\n        {\n          \"dmxRange\": [46, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 4\"\n        },\n        {\n          \"dmxRange\": [56, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 5\"\n        },\n        {\n          \"dmxRange\": [66, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 1\"\n        },\n        {\n          \"dmxRange\": [76, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 2\"\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 3\"\n        },\n        {\n          \"dmxRange\": [96, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 6\"\n        },\n        {\n          \"dmxRange\": [106, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 7\"\n        },\n        {\n          \"dmxRange\": [116, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 8\"\n        },\n        {\n          \"dmxRange\": [126, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 9\"\n        },\n        {\n          \"dmxRange\": [136, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 10\"\n        },\n        {\n          \"dmxRange\": [146, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 11\"\n        },\n        {\n          \"dmxRange\": [156, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change Effect 12\"\n        },\n        {\n          \"dmxRange\": [166, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 4\"\n        },\n        {\n          \"dmxRange\": [176, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 5\"\n        },\n        {\n          \"dmxRange\": [186, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 6\"\n        },\n        {\n          \"dmxRange\": [196, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 7\"\n        },\n        {\n          \"dmxRange\": [206, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 8\"\n        },\n        {\n          \"dmxRange\": [216, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 9\"\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 10\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Transition Effect 11\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Sound Mode Selection\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 1\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [16, 25],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 2\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [26, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 3\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [36, 45],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 4\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [46, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 5\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [56, 65],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 6\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [66, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 7\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [76, 85],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 8\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [86, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 9\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [96, 105],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 10\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [106, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 11\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [116, 125],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 12\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [126, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 13\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [136, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 14\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [146, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 15\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [156, 165],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 16\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [166, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 17\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [176, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 18\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [186, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 19\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [196, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 20\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [206, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 21\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [216, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 22\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [226, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 23\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 24\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Mode 25\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Auto Mode Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"Generic\",\n          \"comment\": \"RGBW color chasing\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 127],\n          \"type\": \"Generic\",\n          \"comment\": \"Color Presets\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"Generic\",\n          \"comment\": \"Color Macros\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Auto Mode Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"Generic\",\n          \"comment\": \"Music Controlled\",\n          \"switchChannels\": {\n            \"Effect Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 21],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [22, 27],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [28, 33],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange Red\",\n          \"colors\": [\"#ff0e00\"]\n        },\n        {\n          \"dmxRange\": [34, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red Orange\",\n          \"colors\": [\"#ff3200\"]\n        },\n        {\n          \"dmxRange\": [40, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff7d00\"]\n        },\n        {\n          \"dmxRange\": [46, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [52, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Shining Gold\",\n          \"colors\": [\"#ffd200\"]\n        },\n        {\n          \"dmxRange\": [58, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [64, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Yellow\",\n          \"colors\": [\"#c8ff00\"]\n        },\n        {\n          \"dmxRange\": [70, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime\",\n          \"colors\": [\"#a0ff00\"]\n        },\n        {\n          \"dmxRange\": [76, 81],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chartreuse\",\n          \"colors\": [\"#6eff00\"]\n        },\n        {\n          \"dmxRange\": [82, 87],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Laser Green\",\n          \"colors\": [\"#46ff00\"]\n        },\n        {\n          \"dmxRange\": [88, 93],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [94, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lawn Green\",\n          \"colors\": [\"#00ff0a\"]\n        },\n        {\n          \"dmxRange\": [100, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Bright Forest Green\",\n          \"colors\": [\"#00ff19\"]\n        },\n        {\n          \"dmxRange\": [106, 111],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Spring Green\",\n          \"colors\": [\"#00ff28\"]\n        },\n        {\n          \"dmxRange\": [112, 117],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emerald\",\n          \"colors\": [\"#00ff46\"]\n        },\n        {\n          \"dmxRange\": [118, 123],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#00ff78\"]\n        },\n        {\n          \"dmxRange\": [124, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [130, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Azure\",\n          \"colors\": [\"#0064ff\"]\n        },\n        {\n          \"dmxRange\": [136, 141],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [142, 147],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Water Ocean Blue\",\n          \"colors\": [\"#1400ff\"]\n        },\n        {\n          \"dmxRange\": [148, 153],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Kingfisher Feathers Blue\",\n          \"colors\": [\"#3200ff\"]\n        },\n        {\n          \"dmxRange\": [154, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Crystaline Purple\",\n          \"colors\": [\"#5000ff\"]\n        },\n        {\n          \"dmxRange\": [160, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#8200ff\"]\n        },\n        {\n          \"dmxRange\": [166, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Electric Purple Violet\",\n          \"colors\": [\"#b400ff\"]\n        },\n        {\n          \"dmxRange\": [172, 177],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Dragon Fruit Purple\",\n          \"colors\": [\"#e100ff\"]\n        },\n        {\n          \"dmxRange\": [178, 183],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [184, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink Magenta\",\n          \"colors\": [\"#ff00dc\"]\n        },\n        {\n          \"dmxRange\": [190, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rose\",\n          \"colors\": [\"#ff0046\"]\n        },\n        {\n          \"dmxRange\": [196, 201],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Morning Sun Red\",\n          \"colors\": [\"#ff0014\"]\n        },\n        {\n          \"dmxRange\": [202, 207],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Absolutely Red\",\n          \"colors\": [\"#ff0007\"]\n        },\n        {\n          \"dmxRange\": [208, 213],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [214, 219],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Pink\",\n          \"colors\": [\"#ff9090\"]\n        },\n        {\n          \"dmxRange\": [220, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter Pink\",\n          \"colors\": [\"#ffc0c0\"]\n        },\n        {\n          \"dmxRange\": [226, 231],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Green\",\n          \"colors\": [\"#90ff90\"]\n        },\n        {\n          \"dmxRange\": [232, 237],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter Green\",\n          \"colors\": [\"#c0ffc0\"]\n        },\n        {\n          \"dmxRange\": [238, 243],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light Blue\",\n          \"colors\": [\"#9090ff\"]\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lighter Blue\",\n          \"colors\": [\"#c0c0ff\"]\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cool White\",\n          \"colors\": [\"#eeeeff\"]\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Auto Mode\",\n        \"Effect Selection\",\n        \"Sound Mode Selection\",\n        \"Effect Parameter\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Mode Selection\",\n        \"Color Presets\",\n        \"Effect Selection\",\n        \"Sound Mode Selection\",\n        \"Effect Speed / Sound Sensitivity\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\"\n      ]\n    },\n    {\n      \"name\": \"39-channel\",\n      \"shortName\": \"39ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Mode Selection\",\n        \"Color Presets\",\n        \"Effect Selection\",\n        \"Sound Mode Selection\",\n        \"Effect Speed / Sound Sensitivity\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"Segment 1\",\n            \"Segment 2\",\n            \"Segment 3\",\n            \"Segment 4\",\n            \"Segment 5\",\n            \"Segment 6\",\n            \"Segment 7\",\n            \"Segment 8\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/stage-tri-led.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Stage TRI LED\",\n  \"categories\": [\"Stand\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"p_0g_8mm3_\", \"Flo Edelmann\"],\n    \"createDate\": \"2018-01-30\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.thomann.de/pics/prod/238663_manual.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_stage_tri_led_bundle_complete.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=ySy35Mulrx0\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1200, 2400, 100],\n    \"weight\": 16,\n    \"power\": 90,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"4x 7x 3W RGB LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1\", \"2\", \"3\", \"4\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"1+2\": [\"1\", \"2\"],\n      \"3+4\": [\"3\", \"4\"],\n      \"Master\": [\"1\", \"2\", \"3\", \"4\"]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Program\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Violet\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [220, 229],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [230, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\",\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"Maintenance\",\n          \"comment\": \"RGB\"\n        },\n        {\n          \"dmxRange\": [10, 249],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Programs\",\n          \"helpWanted\": \"Are individual programs selectable in this capability?\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Sound control\"\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"RGB\",\n      \"shortName\": \"d-P1\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"RGBD\",\n      \"shortName\": \"d-P2\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Program\",\n      \"shortName\": \"d-P5\",\n      \"channels\": [\n        \"Program\",\n        \"Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"Color + Program\",\n      \"shortName\": \"d-P7\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Program\",\n        \"Speed / Sound Sensitivity\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Split\",\n      \"shortName\": \"d-P3\",\n      \"channels\": [\n        \"Red 1+2\",\n        \"Green 1+2\",\n        \"Blue 1+2\",\n        \"Red 3+4\",\n        \"Green 3+4\",\n        \"Blue 3+4\",\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Individual\",\n      \"shortName\": \"d-P4\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Strobe\",\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"Complete\",\n      \"shortName\": \"d-P6\",\n      \"channels\": [\n        \"Mode\",\n        \"Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/vf-1200-dmx-vertifog-co2-fx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"VF-1200 DMX VertiFog CO2 FX\",\n  \"shortName\": \"VF-1200\",\n  \"categories\": [\"Smoke\"],\n  \"meta\": {\n    \"authors\": [\"Hannes Rüger\"],\n    \"createDate\": \"2022-07-19\",\n    \"lastModifyDate\": \"2022-07-19\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/362289_c_362289_v6_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_vf_1200_dmx_vertifog_co2_fx.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i4452p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [305, 170, 390],\n    \"weight\": 6.6,\n    \"power\": 1250,\n    \"DMXconnector\": \"3-pin\"\n  },\n  \"availableChannels\": {\n    \"Fog\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Fog\",\n        \"fogOutputStart\": \"off\",\n        \"fogOutputEnd\": \"strong\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1ch\",\n      \"channels\": [\n        \"Fog\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/wild-wash-132-led-rgb-dmx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Wild Wash 132 LED RGB DMX\",\n  \"shortName\": \"WildWash132LEDRGB\",\n  \"categories\": [\"Strobe\", \"Color Changer\", \"Blinder\", \"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"Max Jöhnk\"],\n    \"createDate\": \"2024-10-14\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_399664_399663_399658_399662_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_wild_wash_132_led_rgb_dmx.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i6100p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [310, 70, 70],\n    \"weight\": 1.05,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [75, 75]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 13],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff0000\"],\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [14, 21],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffbf00\"],\n          \"comment\": \"Amber\"\n        },\n        {\n          \"dmxRange\": [22, 29],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fceea7\"],\n          \"comment\": \"Warm Yellow\"\n        },\n        {\n          \"dmxRange\": [30, 37],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffff00\"],\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [38, 45],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ff00\"],\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [46, 53],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#40e0d0\"],\n          \"comment\": \"Turquoise\"\n        },\n        {\n          \"dmxRange\": [54, 61],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#00ffff\"],\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [62, 69],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#0000ff\"],\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [70, 77],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#bf94e4\"],\n          \"comment\": \"Lavender\"\n        },\n        {\n          \"dmxRange\": [78, 85],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#a17188\"],\n          \"comment\": \"Mauve\"\n        },\n        {\n          \"dmxRange\": [86, 93],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ff00ff\"],\n          \"comment\": \"Magenta\"\n        },\n        {\n          \"dmxRange\": [94, 101],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#fc0fc0\"],\n          \"comment\": \"Pink\"\n        },\n        {\n          \"dmxRange\": [102, 109],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#efebd8\"],\n          \"comment\": \"Warm White\"\n        },\n        {\n          \"dmxRange\": [110, 117],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#ffffff\"],\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [118, 125],\n          \"type\": \"ColorPreset\",\n          \"colors\": [\"#e3e4ed\"],\n          \"comment\": \"Cold White\"\n        },\n        {\n          \"dmxRange\": [126, 128],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [129, 192],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [193, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Strobe Flash Duration\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"510ms\"\n      }\n    },\n    \"Shutter / Strobe Advanced\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 1\",\n      \"shortName\": \"2ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Color Presets\"\n      ]\n    },\n    {\n      \"name\": \"2-channel 2\",\n      \"shortName\": \"2ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Strobe Flash Duration\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Presets\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 3\",\n      \"shortName\": \"3ch3\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe Advanced\",\n        \"Color Presets\",\n        \"Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Shutter / Strobe Advanced\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/wild-wash-648-led-white-dmx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Wild Wash 648 LED White DMX\",\n  \"shortName\": \"WildWash648LEDWhite\",\n  \"comment\": \"The fixture isn't sold anymore.\",\n  \"categories\": [\"Strobe\", \"Blinder\"],\n  \"meta\": {\n    \"authors\": [\"Paul Rogalski\"],\n    \"createDate\": \"2024-10-09\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/399664_c_399664_399663_399658_399662_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_wild_wash_132_led_rgb_dmx.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [335, 182, 93],\n    \"weight\": 3.25,\n    \"power\": 130,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"648x 0.2 W LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [75, 75]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [4, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Dimmer $pixelKey\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        }\n      ]\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Strobe Flash Duration\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"StrobeDuration\",\n        \"durationStart\": \"0ms\",\n        \"durationEnd\": \"510ms\"\n      }\n    },\n    \"Shutter / Strobe Advanced\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 33],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [34, 56],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [57, 79],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [80, 102],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [103, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\",\n          \"durationStart\": \"5s\",\n          \"durationEnd\": \"1s\"\n        },\n        {\n          \"dmxRange\": [128, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"30Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Strobe Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"This range is missing in the manual. Has it actually no function?\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic strobe programs with alternating segments\"\n        }\n      ]\n    },\n    \"Strobe Program Speed\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"helpWanted\": \"This range is missing in the manual. Has it actually no function?\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"Speed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Shutter / Strobe\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 1\",\n      \"shortName\": \"3ch1\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Shutter / Strobe\",\n        \"Strobe Flash Duration\"\n      ]\n    },\n    {\n      \"name\": \"3-channel 2\",\n      \"shortName\": \"3ch2\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Shutter / Strobe Advanced\",\n        \"Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Shutter / Strobe Advanced\",\n        \"Strobe Programs\",\n        \"Strobe Program Speed\",\n        \"Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer Master\",\n        \"Shutter / Strobe\",\n        \"Strobe Flash Duration\",\n        \"Dimmer 1\",\n        \"Dimmer 2\",\n        \"Dimmer 3\",\n        \"Dimmer 4\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/xbrick-full-colour.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"xBrick Full-Colour\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"fintch\"],\n    \"createDate\": \"2023-02-11\",\n    \"lastModifyDate\": \"2024-11-23\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2022-06-15\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.4.1)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_259187_v4_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_xbrick_fullcolour_16x3w.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i1301p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [310, 175, 72],\n    \"weight\": 3,\n    \"power\": 60,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1A\", \"1B\", null, \"2A\", \"2B\", null, \"3A\", \"3B\", null, \"4A\", \"4B\"],\n        [\"1C\", \"1D\", null, \"2C\", \"2D\", null, \"3C\", \"3D\", null, \"4C\", \"4D\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"All\": \"all\",\n      \"1\": { \"name\": [\"^1[A-D]$\"] },\n      \"2\": { \"name\": [\"^2[A-D]$\"] },\n      \"3\": { \"name\": [\"^3[A-D]$\"] },\n      \"4\": { \"name\": [\"^4[A-D]$\"] }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Are the automatically added speed values correct?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"All\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Master Dimmer\",\n        \"Strobe Speed\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1\", \"2\", \"3\", \"4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Master Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/xbrick-quad-16x8w-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"xBrick Quad 16x8W RGBW\",\n  \"shortName\": \"xBrick RGBW\",\n  \"categories\": [\"Color Changer\", \"Strobe\"],\n  \"meta\": {\n    \"authors\": [\"Maximilian B.\", \"Luke Nelson\"],\n    \"createDate\": \"2023-10-09\",\n    \"lastModifyDate\": \"2023-10-09\"\n  },\n  \"comment\": \"4 Clusters of 4 RGBW LEDs (4x4)\",\n  \"links\": {\n    \"productPage\": [\n      \"https://www.thomann.de/stairville_xbrick_quad_16x8w_rgbw.htm\"\n    ],\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_385641_v4_en_online.pdf\",\n      \"https://images.thomann.de/pics/atg/atgdata/document/manual/c_385641_r4_en_online.pdf\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i5704p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [315, 88, 195],\n    \"weight\": 4.3,\n    \"power\": 125,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"1A\", \"1B\", null, \"2A\", \"2B\", null, \"3A\", \"3B\", null, \"4A\", \"4B\"],\n        [\"1C\", \"1D\", null, \"2C\", \"2D\", null, \"3C\", \"3D\", null, \"4C\", \"4D\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"All\": \"all\",\n      \"1\": { \"name\": [\"^1[A-D]$\"] },\n      \"2\": { \"name\": [\"^2[A-D]$\"] },\n      \"3\": { \"name\": [\"^3[A-D]$\"] },\n      \"4\": { \"name\": [\"^4[A-D]$\"] }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Intensity red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Intensity green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Intensity blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Intensity white\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\",\n        \"brightnessStart\": \"0%\",\n        \"brightnessEnd\": \"100%\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Function select\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"Intensity red\",\n            \"Intensity green / NoFunctionG\": \"Intensity green\",\n            \"Intensity blue / NoFunctionB\": \"Intensity blue\",\n            \"Intensity white / NoFunctionW\": \"Intensity white\",\n            \"Dimmer / NoFunctionD\": \"NoFunctionD\",\n            \"Strobe / NoFunctionS\": \"NoFunctionS\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 9],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#00ffff\"],\n          \"comment\": \"Cyan\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 14],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#800080\"],\n          \"comment\": \"Purple\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [15, 19],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#ffc0cb\"],\n          \"comment\": \"Pink\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [20, 24],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#ffa500\"],\n          \"comment\": \"Orange\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [25, 29],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#f4fdff\"],\n          \"comment\": \"Cold White\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [30, 34],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#ff4040\"],\n          \"comment\": \"Bright Red\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [35, 39],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#57fd57\"],\n          \"comment\": \"Bright Green\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 44],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#3232ff\"],\n          \"comment\": \"Bright Blue\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [45, 49],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#ffff00\"],\n          \"comment\": \"Yellow\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 54],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#fdf4dc\"],\n          \"comment\": \"Warm White\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [55, 59],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#ff0000\"],\n          \"comment\": \"Red\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [60, 64],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#00ff00\"],\n          \"comment\": \"Green\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [65, 69],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#0000ff\"],\n          \"comment\": \"Blue\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [70, 74],\n          \"type\": \"ColorPreset\",\n          \"colorsStart\": [\"#000000\"],\n          \"colorsEnd\": [\"#ffbf00\"],\n          \"comment\": \"Amber\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [75, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"All\",\n          \"helpWanted\": \"What does this do?\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"NoFunction\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 86],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 02\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [87, 93],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 03\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [94, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 04\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 05\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [108, 114],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 06\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [115, 121],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 07\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [122, 128],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 08\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [129, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 09\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [136, 142],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [143, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [150, 156],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [157, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [164, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 14\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 177],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 15\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [178, 184],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 16\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [185, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 17\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 198],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 18\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [199, 205],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 19\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [206, 212],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 20\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [213, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 21\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [220, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 22\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [227, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 23\",\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound controlled (slow)\",\n          \"comment\": \"Sound-controlled operation, slow transition Programs 02 to 23\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Microphone Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound controlled (fast)\",\n          \"comment\": \"Sound-controlled operation, fast transition Programs 02 to 23\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Intensity red / NoFunctionR\": \"NoFunctionR\",\n            \"Intensity green / NoFunctionG\": \"NoFunctionG\",\n            \"Intensity blue / NoFunctionB\": \"NoFunctionB\",\n            \"Intensity white / NoFunctionW\": \"NoFunctionW\",\n            \"Dimmer / NoFunctionD\": \"Dimmer\",\n            \"Strobe / NoFunctionS\": \"Strobe\",\n            \"NoFunction / Program Speed / Microphone Sensitivity\": \"Microphone Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"Slow to Fast or Fast to Slow?\"\n      }\n    },\n    \"Microphone Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\",\n        \"helpWanted\": \"Low to High or High to Low?\"\n      }\n    },\n    \"NoFunction\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunctionD\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunctionS\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunctionR\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunctionG\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunctionB\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"NoFunctionW\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"All\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"All\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Intensity red / NoFunctionR\",\n        \"Intensity green / NoFunctionG\",\n        \"Intensity blue / NoFunctionB\",\n        \"Intensity white / NoFunctionW\",\n        \"Dimmer / NoFunctionD\",\n        \"Strobe / NoFunctionS\",\n        \"Function select\",\n        \"NoFunction / Program Speed / Microphone Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1\", \"2\", \"3\", \"4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\"1\", \"2\", \"3\", \"4\"],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/stairville/z120m-par-64-led-rgbw-120w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Z120M Par 64 LED RGBW 120W\",\n  \"categories\": [\"Dimmer\", \"Strobe\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"youri fernandez\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-01-29\",\n    \"lastModifyDate\": \"2022-01-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/451128_c_451128_r3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/stairville_z120m_par_64_led_rgbw_120w.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=d6hIcfGas6o\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [491, 275, 224],\n    \"weight\": 3.24,\n    \"power\": 125,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"1× 120W COB RGBW 4in1 LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [9.5, 43]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [18, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ff7f00\"]\n        },\n        {\n          \"dmxRange\": [30, 41],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm Yellow\",\n          \"colors\": [\"#ffd000\"]\n        },\n        {\n          \"dmxRange\": [42, 53],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff7f\"]\n        },\n        {\n          \"dmxRange\": [54, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [66, 77],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [78, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cobalt Blue\",\n          \"colors\": [\"#00a2ff\"]\n        },\n        {\n          \"dmxRange\": [90, 101],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [102, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lilac\",\n          \"colors\": [\"#9900ff\"]\n        },\n        {\n          \"dmxRange\": [114, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [126, 137],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Crimson Red\",\n          \"colors\": [\"#da001d\"]\n        },\n        {\n          \"dmxRange\": [138, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ff80ca\"]\n        },\n        {\n          \"dmxRange\": [150, 161],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm White\",\n          \"colors\": [\"#ffeebe\"]\n        },\n        {\n          \"dmxRange\": [162, 173],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [174, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cold White\",\n          \"colors\": [\"#d1fdff\"]\n        },\n        {\n          \"dmxRange\": [186, 220],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [221, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 35],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [36, 55],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2800K\"\n        },\n        {\n          \"dmxRange\": [56, 75],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"dmxRange\": [76, 95],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3200K\"\n        },\n        {\n          \"dmxRange\": [96, 115],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3500K\"\n        },\n        {\n          \"dmxRange\": [116, 135],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4000K\"\n        },\n        {\n          \"dmxRange\": [136, 155],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4500K\"\n        },\n        {\n          \"dmxRange\": [156, 175],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5000K\"\n        },\n        {\n          \"dmxRange\": [176, 195],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"5500K\"\n        },\n        {\n          \"dmxRange\": [196, 215],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [216, 235],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6500K\"\n        },\n        {\n          \"dmxRange\": [236, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7200K\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [16, 30],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [31, 90],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [91, 105],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [106, 165],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"1Hz\",\n          \"speedEnd\": \"25Hz\"\n        },\n        {\n          \"dmxRange\": [166, 180],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [181, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true,\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Show 1: Color change\"\n        },\n        {\n          \"dmxRange\": [96, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Show 2: Strobe effect color\"\n        },\n        {\n          \"dmxRange\": [176, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Show 3: Color fade\"\n        }\n      ]\n    },\n    \"Program Speed / Sound Control\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 250],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"high\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Color Macros\",\n        \"Color Temperature\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Macros\",\n        \"Color Temperature\",\n        \"Auto Programs\",\n        \"Program Speed / Sound Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/starway/servo-color-4k.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Servo Color 4K\",\n  \"shortName\": \"ServoColor4K\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"MullRR\", \"Flo Edelmann\"],\n    \"createDate\": \"2020-03-29\",\n    \"lastModifyDate\": \"2020-03-29\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://en.starway.eu/telechargements/?doc=474030\"\n    ],\n    \"productPage\": [\n      \"https://en.starway.eu/servo-color-4k-conditionne-en-carton-wash-19x15w-rgbw-2\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [314, 370, 222],\n    \"weight\": 9,\n    \"power\": 300,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"19× 15W RGBW LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [10, 48]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"defaultValue\": 32768,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"PanTiltSpeed\",\n          \"speed\": \"fast\",\n          \"comment\": \"Smooth movement\"\n        },\n        {\n          \"dmxRange\": [4, 255],\n          \"type\": \"PanTiltSpeed\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"fineChannelAliases\": [\"Dimmer fine\"],\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"defaultValue\": 8,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [11, 90],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [91, 170],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [171, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"randomTiming\": true,\n          \"comment\": \"synchronized\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"defaultValue\": 255,\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"wide\",\n        \"angleEnd\": \"narrow\"\n      }\n    },\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"defaultValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"defaultValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"defaultValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"defaultValue\": \"100%\",\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Virtual Color Wheel\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [1, 1],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"10000K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [2, 2],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"8000K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [3, 3],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"6500K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [4, 4],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5600K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"5000K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [6, 6],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4500K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [7, 7],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"4000K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 8],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3200K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [9, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"3000K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"colorTemperature\": \"2700K\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 11],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#f1525b\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [12, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red … Yellow\",\n          \"colorsStart\": [\"#f1525b\"],\n          \"colorsEnd\": [\"#e5ed51\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 51],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#e5ed51\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [52, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow … Green\",\n          \"colorsStart\": [\"#e5ed51\"],\n          \"colorsEnd\": [\"#7fce6d\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [91, 91],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#7fce6d\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [92, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green … Blue\",\n          \"colorsStart\": [\"#7fce6d\"],\n          \"colorsEnd\": [\"#6377bd\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 171],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#6377bd\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [172, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue … Magenta\",\n          \"colorsStart\": [\"#6377bd\"],\n          \"colorsEnd\": [\"#bb65b7\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 211],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#bb65b7\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [212, 250],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta … Red\",\n          \"colorsStart\": [\"#bb65b7\"],\n          \"colorsEnd\": [\"#f1525b\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 251],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#f1525b\"],\n          \"switchChannels\": {\n            \"Effect Speed\": \"Color Fade Time\"\n          }\n        },\n        {\n          \"dmxRange\": [252, 253],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"virtual color wheel rotation (forwards)\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Virtual Color Wheel Rotation Speed Forwards\"\n          }\n        },\n        {\n          \"dmxRange\": [254, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"comment\": \"virtual color wheel rotation (backwards)\",\n          \"switchChannels\": {\n            \"Effect Speed\": \"Virtual Color Wheel Rotation Speed Backwards\"\n          }\n        }\n      ]\n    },\n    \"Color Fade Time\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectDuration\",\n        \"durationStart\": \"10s\",\n        \"durationEnd\": \"1s\"\n      }\n    },\n    \"Virtual Color Wheel Rotation Speed Forwards\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Virtual Color Wheel Rotation Speed Backwards\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow reverse\",\n        \"speedEnd\": \"fast reverse\"\n      }\n    },\n    \"Control\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LED calibration off\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"Maintenance\",\n          \"comment\": \"LED calibration on\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode regulation\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Fan mode silent\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"NoFunction\",\n          \"comment\": \"for future use\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"NoFunction\",\n          \"comment\": \"for future use\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Pan reset\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Tilt reset\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Zoom reset\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"Maintenance\",\n          \"comment\": \"System reset\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"15-channel 8bit\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Zoom\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Virtual Color Wheel\",\n        \"Effect Speed\",\n        \"Control\"\n      ]\n    },\n    {\n      \"name\": \"20-channel 16bit\",\n      \"shortName\": \"20ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Dimmer fine\",\n        \"Shutter / Strobe\",\n        \"Zoom\",\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\",\n        \"Virtual Color Wheel\",\n        \"Effect Speed\",\n        \"Control\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/starway/stickolor-1210uhd.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"SticKolor 1210UHD\",\n  \"shortName\": \"SWSticKolor1210\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Robin\"],\n    \"createDate\": \"2019-03-04\",\n    \"lastModifyDate\": \"2019-03-04\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://web.archive.org/web/20201025052441/https://en.star-way.com/telechargements/?doc=450576\"\n    ],\n    \"productPage\": [\n      \"https://web.archive.org/web/20210614082955/https://en.star-way.com/stickolor-1210uhd\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 21\n  },\n  \"physical\": {\n    \"dimensions\": [900, 140, 150],\n    \"weight\": 6.2,\n    \"power\": 145,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"10W RGBWAUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [50, 50]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [12, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Macros\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [10, 17],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [18, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [26, 33],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [34, 41],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [42, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [50, 57],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [58, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RW + UV\",\n          \"colors\": [\"#ff8080\", \"#8800ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [66, 73],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RA + UV\",\n          \"colors\": [\"#ff6000\", \"#8800ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [74, 81],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BWA\",\n          \"colors\": [\"#ffdfff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [82, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"BW + UV\",\n          \"colors\": [\"#8080ff\", \"#8800ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [90, 97],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBW + UV\",\n          \"colors\": [\"#ff80ff\", \"#8800ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [98, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RBA + UV\",\n          \"colors\": [\"#ff6080\", \"#8800ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [106, 113],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RWA + UV\",\n          \"colors\": [\"#ff9555\", \"#8800ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [114, 121],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"GBWA\",\n          \"colors\": [\"#baffba\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [122, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"RGBW + UV\",\n          \"colors\": [\"#ffeaaa\", \"#8800ff\"],\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [130, 137],\n          \"type\": \"Effect\",\n          \"effectName\": \"Dream\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [138, 145],\n          \"type\": \"Effect\",\n          \"effectName\": \"Meteor\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [146, 153],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [154, 161],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [162, 169],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 1\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [170, 177],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 2\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [178, 185],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 3\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [186, 193],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 4\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [194, 201],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 5\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [202, 209],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 6\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [210, 217],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 7\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [218, 225],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 8\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [226, 233],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 9\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [234, 241],\n          \"type\": \"Effect\",\n          \"effectName\": \"Flow 10\",\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Macro Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [242, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Macro Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Macro Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        \"UV Master\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        \"UV Master\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Amber Master\",\n        \"UV Master\",\n        \"Color Macros\",\n        \"Macro Speed / Sound Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"72-channel\",\n      \"shortName\": \"72ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\",\n            \"UV $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"76-channel\",\n      \"shortName\": \"76ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\",\n            \"Amber $pixelKey\",\n            \"UV $pixelKey\"\n          ]\n        },\n        \"Color Macros\",\n        \"Macro Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/studio-due/light-deflector.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Light Deflector\",\n  \"categories\": [\"Scanner\"],\n  \"meta\": {\n    \"authors\": [\"Manu Larue\"],\n    \"createDate\": \"2020-03-24\",\n    \"lastModifyDate\": \"2024-11-23\"\n  },\n  \"links\": {\n    \"other\": [\n      \"http://backstageworld.com/StudioDue/deflector.html\",\n      \"https://www.forum.licht-geluid.nl/forum/licht-fora/licht-forum-foto-s/3364-studio-due-light-deflector?t=3267\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [320, 460, 130],\n    \"weight\": 5.0,\n    \"power\": 69\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"360deg\"\n      }\n    },\n    \"Tilt Spin\": {\n      \"capability\": {\n        \"type\": \"TiltContinuous\",\n        \"helpWanted\": \"At which DMX values is continuous tilt disabled? Where does it spin clockwise / counter-clockwise?\",\n        \"speedStart\": \"0.166667rpm\",\n        \"speedEnd\": \"30rpm\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Reset\": {\n      \"capability\": {\n        \"type\": \"Maintenance\",\n        \"comment\": \"Reset Pan/Tilt\",\n        \"helpWanted\": \"At which DMX values does the fixture perform a reset?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8 bit 4-channel\",\n      \"shortName\": \"8bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Tilt Spin\",\n        \"Pan/Tilt Speed\"\n      ]\n    },\n    {\n      \"name\": \"16 bit 7-channel\",\n      \"shortName\": \"16bit\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Tilt Spin\",\n        \"Pan/Tilt Speed\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/sun-star/g-2011-nova.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"G-2011 / NOVA\",\n  \"categories\": [\"Laser\"],\n  \"meta\": {\n    \"authors\": [\"Nils Van Zuijlen\"],\n    \"createDate\": \"2018-12-08\",\n    \"lastModifyDate\": \"2018-12-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://sunstarprolight.com.ar/manuales/NOVA-3D.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=FatnsLLsyKA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [150, 130, 210],\n    \"weight\": 8,\n    \"power\": 30,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"Green laser 532nm\"\n    }\n  },\n  \"availableChannels\": {\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 49],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [50, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"DMX\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"Effect\",\n          \"effectName\": \"Audio\",\n          \"soundControlled\": true\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto\"\n        }\n      ]\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"precedence\": \"LTP\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 1\",\n          \"helpWanted\": \"Is this actually NoFunction? How to disable programs?\"\n        },\n        {\n          \"dmxRange\": [4, 7],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 2\"\n        },\n        {\n          \"dmxRange\": [8, 11],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 3\"\n        },\n        {\n          \"dmxRange\": [12, 15],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 4\"\n        },\n        {\n          \"dmxRange\": [16, 19],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 5\"\n        },\n        {\n          \"dmxRange\": [20, 23],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 6\"\n        },\n        {\n          \"dmxRange\": [24, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 7\"\n        },\n        {\n          \"dmxRange\": [28, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 8\"\n        },\n        {\n          \"dmxRange\": [32, 35],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 9\"\n        },\n        {\n          \"dmxRange\": [36, 39],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 10\"\n        },\n        {\n          \"dmxRange\": [40, 43],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 11\"\n        },\n        {\n          \"dmxRange\": [44, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 12\"\n        },\n        {\n          \"dmxRange\": [48, 51],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 13\"\n        },\n        {\n          \"dmxRange\": [52, 55],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 14\"\n        },\n        {\n          \"dmxRange\": [56, 59],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 15\"\n        },\n        {\n          \"dmxRange\": [60, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 16\"\n        },\n        {\n          \"dmxRange\": [64, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 17\"\n        },\n        {\n          \"dmxRange\": [68, 71],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 18\"\n        },\n        {\n          \"dmxRange\": [72, 75],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 19\"\n        },\n        {\n          \"dmxRange\": [76, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 20\"\n        },\n        {\n          \"dmxRange\": [80, 83],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 21\"\n        },\n        {\n          \"dmxRange\": [84, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 22\"\n        },\n        {\n          \"dmxRange\": [88, 91],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 23\"\n        },\n        {\n          \"dmxRange\": [92, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 24\"\n        },\n        {\n          \"dmxRange\": [96, 99],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 25\"\n        },\n        {\n          \"dmxRange\": [100, 103],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 26\"\n        },\n        {\n          \"dmxRange\": [104, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 27\"\n        },\n        {\n          \"dmxRange\": [108, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 28\"\n        },\n        {\n          \"dmxRange\": [112, 115],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 29\"\n        },\n        {\n          \"dmxRange\": [116, 119],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 30\"\n        },\n        {\n          \"dmxRange\": [120, 123],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 31\"\n        },\n        {\n          \"dmxRange\": [124, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 32\"\n        },\n        {\n          \"dmxRange\": [128, 131],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 33\"\n        },\n        {\n          \"dmxRange\": [132, 135],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 34\"\n        },\n        {\n          \"dmxRange\": [136, 139],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 35\"\n        },\n        {\n          \"dmxRange\": [140, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 36\"\n        },\n        {\n          \"dmxRange\": [144, 147],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 37\"\n        },\n        {\n          \"dmxRange\": [148, 151],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 38\"\n        },\n        {\n          \"dmxRange\": [152, 155],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 39\"\n        },\n        {\n          \"dmxRange\": [156, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 40\"\n        },\n        {\n          \"dmxRange\": [160, 163],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 41\"\n        },\n        {\n          \"dmxRange\": [164, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 42\"\n        },\n        {\n          \"dmxRange\": [168, 171],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 43\"\n        },\n        {\n          \"dmxRange\": [172, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 44\"\n        },\n        {\n          \"dmxRange\": [176, 179],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 45\"\n        },\n        {\n          \"dmxRange\": [180, 183],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 46\"\n        },\n        {\n          \"dmxRange\": [184, 187],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 47\"\n        },\n        {\n          \"dmxRange\": [188, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 48\"\n        },\n        {\n          \"dmxRange\": [192, 195],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 49\"\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 50\"\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 51\"\n        },\n        {\n          \"dmxRange\": [204, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 52\"\n        },\n        {\n          \"dmxRange\": [208, 211],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 53\"\n        },\n        {\n          \"dmxRange\": [212, 215],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 54\"\n        },\n        {\n          \"dmxRange\": [216, 219],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 55\"\n        },\n        {\n          \"dmxRange\": [220, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 56\"\n        },\n        {\n          \"dmxRange\": [224, 227],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 57\"\n        },\n        {\n          \"dmxRange\": [228, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 58\"\n        },\n        {\n          \"dmxRange\": [232, 235],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 59\"\n        },\n        {\n          \"dmxRange\": [236, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 60\"\n        },\n        {\n          \"dmxRange\": [240, 243],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 61\"\n        },\n        {\n          \"dmxRange\": [244, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 62\"\n        },\n        {\n          \"dmxRange\": [248, 251],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 63\"\n        },\n        {\n          \"dmxRange\": [252, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 64\"\n        }\n      ]\n    },\n    \"Horizontal Position\": {\n      \"defaultValue\": \"50%\",\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"BeamPosition\",\n        \"horizontalAngleStart\": \"-15.5deg\",\n        \"horizontalAngleEnd\": \"15.5deg\"\n      }\n    },\n    \"Vertical Position\": {\n      \"defaultValue\": \"50%\",\n      \"precedence\": \"LTP\",\n      \"capability\": {\n        \"type\": \"BeamPosition\",\n        \"verticalAngleStart\": \"-15.5deg\",\n        \"verticalAngleEnd\": \"15.5deg\"\n      }\n    },\n    \"Effect Speed\": {\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Rotation Speed\": {\n      \"precedence\": \"HTP\",\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"speedStart\": \"fast CW\",\n        \"speedEnd\": \"slow CW\",\n        \"helpWanted\": \"Or is this CCW (counter-clockwise)?\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Default\",\n      \"channels\": [\n        \"Mode\",\n        \"Programs\",\n        \"Horizontal Position\",\n        \"Vertical Position\",\n        \"Effect Speed\",\n        \"Rotation Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/tecshow/nebula-18.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Nebula 18\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\", \"JonahKr\"],\n    \"createDate\": \"2021-07-06\",\n    \"lastModifyDate\": \"2021-07-06\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://amproweb.com/_admin/files/750646Tecshow%20Nebula%2018%20B.pdf\"\n    ],\n    \"productPage\": [\n      \"http://tecshow.amproweb.com/en/nebula18\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=i1yWs5f5GKQ\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [310, 125, 310],\n    \"weight\": 6,\n    \"DMXconnector\": \"3-pin\",\n    \"power\": 216,\n    \"bulb\": {\n      \"type\": \"18 RGBAW+UV 12W LEDs\",\n      \"lumens\": 4389\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"Speed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the light constantly on or off?\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Color\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n      }\n    },\n    \"Strobe Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\",\n          \"helpWanted\": \"The manual doesn't specify the exact behavior.\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"helpWanted\": \"The manual doesn't specify the exact behavior.\"\n        },\n        {\n          \"dmxRange\": [150, 199],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Strobe effect 1\",\n          \"helpWanted\": \"The manual doesn't specify the exact behavior.\"\n        },\n        {\n          \"dmxRange\": [200, 245],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"comment\": \"Strobe effect 2\",\n          \"helpWanted\": \"The manual doesn't specify the exact behavior.\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"100%\"\n        }\n      ]\n    },\n    \"Color Walking\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"White - Red - Yellow - Pink - Green - Orange - Blue - Light salmon pink\"\n        }\n      ]\n    },\n    \"Effect Speed / Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 199],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\",\n          \"helpWanted\": \"Is this capability low…high or high…low?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"UV\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"11ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"UV\",\n        \"Amber\",\n        \"Color\",\n        \"Strobe Effect\",\n        \"Color Walking\",\n        \"Effect Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/tecshow/nebula-6.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Nebula 6\",\n  \"shortName\": \"nebula6\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Esteban Zallocco\"],\n    \"createDate\": \"2022-01-03\",\n    \"lastModifyDate\": \"2026-01-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"http://amproweb.com/_admin/files/02b55bNebula%206%20B.pdf\"\n    ],\n    \"productPage\": [\n      \"http://tecshow.amproweb.com/es/nebula6\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=IQQqpnKiArE\"\n    ],\n    \"other\": [\n      \"http://amproweb.com/_admin/files/6a5bd4Nebula6.zip\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [260, 260, 360],\n    \"weight\": 1,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 99],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"100Hz\"\n        },\n        {\n          \"dmxRange\": [100, 149],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"100Hz\",\n          \"speedEnd\": \"0Hz\",\n          \"helpWanted\": \"A strobe speed of 100Hz is highly unlikely. Is there really an increasing strobe speed between DMX values 8 and 99 and then a decreasing strobe speed between DMX values 100 and 149?\"\n        },\n        {\n          \"dmxRange\": [150, 199],\n          \"type\": \"Effect\",\n          \"effectName\": \"strobe1\"\n        },\n        {\n          \"dmxRange\": [200, 245],\n          \"type\": \"Effect\",\n          \"effectName\": \"strobe2\",\n          \"helpWanted\": \"What are these two strobe effects exactly?\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speed\": \"200Hz\",\n          \"helpWanted\": \"What can be selected here? A strobe speed of 200Hz is highly unlikely. Is the fastest strobe speed at DMX values 246 to 255 the same as between DMX values 99 and 100?\"\n        }\n      ]\n    },\n    \"Color Wheel Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"red,yellow,magenta,green,orange,cyan,pink\",\n          \"colors\": [\"#ff0000\", \"#ffff00\", \"#ff00ff\", \"#00ff00\", \"#ff5500\", \"#008888\", \"#ff3355\"],\n          \"helpWanted\": \"Is this the activation of an auto color change effect? Is there a smooth or hard transition between those colors? Are there any differences between the DMX values?\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 199],\n          \"type\": \"EffectSpeed\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Wheel Rotation\",\n        \"Color Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/tiptop-stage-light/3-10w-battery-led-wedge-par.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"3*10W Battery LED WEDGE PAR\",\n  \"shortName\": \"TP-G3047-4IN1\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"DJMaxone.de\"],\n    \"createDate\": \"2018-12-12\",\n    \"lastModifyDate\": \"2018-12-12\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.11.2\",\n      \"date\": \"2018-12-12\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.11.2)\"\n    }\n  },\n  \"helpWanted\": \"Can you provide the link to a manual or a YouTube/Vimeo/Facebook video?\",\n  \"links\": {\n    \"productPage\": [\n      \"https://www.tiptopstagelight.com/products/triangle-led-par-light/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [118, 105, 114],\n    \"weight\": 0.35,\n    \"power\": 36,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3× 10W RGBW LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Program\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Strobe\"\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\"\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Dimmer\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Change\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Function speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Program\",\n        \"Function speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/tmb/solaris-flare.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Solaris Flare\",\n  \"shortName\": \"TMBFlare\",\n  \"categories\": [\"Strobe\", \"Blinder\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-03-15\",\n    \"lastModifyDate\": \"2018-08-09\"\n  },\n  \"comment\": \"Flares with serial numbers that contain “14R” have RDM functionality.\\nExample: xxxxxx-14R-xxxx\",\n  \"links\": {\n    \"manual\": [\n      \"https://web.archive.org/web/20190219222320/http://pub.tmb.com/solaris/pdf/Solaris-Flare-Manual.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=qTn9OWkmF9Y\",\n      \"https://www.youtube.com/watch?v=dUtpecqEQRA\"\n    ]\n  },\n  \"rdm\": {\n    \"modelId\": 1703,\n    \"softwareVersion\": \"9.3C\"\n  },\n  \"physical\": {\n    \"dimensions\": [210, 232, 497],\n    \"weight\": 9.5,\n    \"power\": 1000,\n    \"DMXconnector\": \"5-pin\",\n    \"bulb\": {\n      \"type\": \"96 10W RGBW Cree LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [36, 36]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [16, 6, 1],\n    \"pixelGroups\": {\n      \"1-Pixel\": \"all\",\n      \"2V-Pixel 1\": { \"x\": [\"<=8\"] },\n      \"2V-Pixel 2\": { \"x\": [\">=9\"] },\n      \"2H-Pixel 1\": { \"y\": [\"<=3\"] },\n      \"2H-Pixel 2\": { \"y\": [\">=4\"] },\n      \"3-Pixel 1\": { \"y\": [\"<=2\"] },\n      \"3-Pixel 2\": { \"y\": [\">=3\", \"<=4\"] },\n      \"3-Pixel 3\": { \"y\": [\">=5\"] },\n      \"4-Pixel 1\": { \"x\": [\"<=8\"], \"y\": [\"<=3\"] },\n      \"4-Pixel 2\": { \"x\": [\">=9\"], \"y\": [\"<=3\"] },\n      \"4-Pixel 3\": { \"x\": [\"<=8\"], \"y\": [\">=4\"] },\n      \"4-Pixel 4\": { \"x\": [\">=9\"], \"y\": [\">=4\"] },\n      \"6V-Pixel 1\": { \"x\": [\"<=8\"], \"y\": [\"<=2\"] },\n      \"6V-Pixel 2\": { \"x\": [\">=9\"], \"y\": [\"<=2\"] },\n      \"6V-Pixel 3\": { \"x\": [\"<=8\"], \"y\": [\">=3\", \"<=4\"] },\n      \"6V-Pixel 4\": { \"x\": [\">=9\"], \"y\": [\">=3\", \"<=4\"] },\n      \"6V-Pixel 5\": { \"x\": [\"<=8\"], \"y\": [\">=5\"] },\n      \"6V-Pixel 6\": { \"x\": [\">=9\"], \"y\": [\">=5\"] },\n      \"6H-Pixel 1\": { \"y\": [\"=1\"] },\n      \"6H-Pixel 2\": { \"y\": [\"=2\"] },\n      \"6H-Pixel 3\": { \"y\": [\"=3\"] },\n      \"6H-Pixel 4\": { \"y\": [\"=4\"] },\n      \"6H-Pixel 5\": { \"y\": [\"=5\"] },\n      \"6H-Pixel 6\": { \"y\": [\"=6\"] },\n      \"12-Pixel 1\": { \"x\": [\"<=8\"], \"y\": [\"=1\"] },\n      \"12-Pixel 2\": { \"x\": [\"<=8\"], \"y\": [\"=2\"] },\n      \"12-Pixel 3\": { \"x\": [\">=9\"], \"y\": [\"=1\"] },\n      \"12-Pixel 4\": { \"x\": [\">=9\"], \"y\": [\"=2\"] },\n      \"12-Pixel 5\": { \"x\": [\"<=8\"], \"y\": [\"=3\"] },\n      \"12-Pixel 6\": { \"x\": [\"<=8\"], \"y\": [\"=4\"] },\n      \"12-Pixel 7\": { \"x\": [\">=9\"], \"y\": [\"=3\"] },\n      \"12-Pixel 8\": { \"x\": [\">=9\"], \"y\": [\"=4\"] },\n      \"12-Pixel 9\": { \"x\": [\"<=8\"], \"y\": [\"=5\"] },\n      \"12-Pixel 10\": { \"x\": [\"<=8\"], \"y\": [\"=6\"] },\n      \"12-Pixel 11\": { \"x\": [\">=9\"], \"y\": [\"=5\"] },\n      \"12-Pixel 12\": { \"x\": [\">=9\"], \"y\": [\"=6\"] }\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"fineChannelAliases\": [\"Red fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"fineChannelAliases\": [\"Green fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"fineChannelAliases\": [\"Blue fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"fineChannelAliases\": [\"White fine\"],\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Flash intensity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"Intensity\",\n          \"brightness\": \"off\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"dark\",\n          \"brightnessEnd\": \"bright\"\n        }\n      ]\n    },\n    \"Flash duration\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"StrobeDuration\",\n          \"durationStart\": \"0ms\",\n          \"durationEnd\": \"650ms\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"HYPER\"\n        }\n      ]\n    },\n    \"Flash rate\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"25Hz\"\n        }\n      ]\n    },\n    \"Flash effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [5, 5],\n          \"type\": \"Effect\",\n          \"effectName\": \"Wash Override (only in RGB/RGBW Strobe modes)\"\n        },\n        {\n          \"dmxRange\": [6, 42],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\"\n        },\n        {\n          \"dmxRange\": [43, 85],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\"\n        },\n        {\n          \"dmxRange\": [86, 128],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\"\n        },\n        {\n          \"dmxRange\": [129, 171],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [172, 214],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Lightning\"\n        },\n        {\n          \"dmxRange\": [215, 240],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Spikes\"\n        },\n        {\n          \"dmxRange\": [241, 245],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Burst\",\n          \"comment\": \"use rate at full\"\n        },\n        {\n          \"dmxRange\": [246, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Meltdown: Random Pixels with solid background\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Meltdown: Random pixels with burst background\"\n        }\n      ]\n    },\n    \"Red Strobe\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green Strobe\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue Strobe\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White Strobe\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"templateChannels\": {\n    \"$pixelKey Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"$pixelKey Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"$pixelKey Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"$pixelKey White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"Basic RGB 8bit\",\n      \"shortName\": \"RGB8bit\",\n      \"rdmPersonalityIndex\": 1,\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"Basic RGB 16bit\",\n      \"shortName\": \"RGB16bit\",\n      \"rdmPersonalityIndex\": 2,\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\"\n      ]\n    },\n    {\n      \"name\": \"Basic RGBW 8bit\",\n      \"shortName\": \"RGBW8bit\",\n      \"rdmPersonalityIndex\": 3,\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"Basic RGBW 16bit\",\n      \"shortName\": \"RGBW16bit\",\n      \"rdmPersonalityIndex\": 4,\n      \"channels\": [\n        \"Red\",\n        \"Red fine\",\n        \"Green\",\n        \"Green fine\",\n        \"Blue\",\n        \"Blue fine\",\n        \"White\",\n        \"White fine\"\n      ]\n    },\n    {\n      \"name\": \"Strobe Only\",\n      \"shortName\": \"strobe\",\n      \"rdmPersonalityIndex\": 5,\n      \"channels\": [\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\"\n      ]\n    },\n    {\n      \"name\": \"RGB Strobe\",\n      \"shortName\": \"RGBstrobe\",\n      \"rdmPersonalityIndex\": 6,\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\"\n      ]\n    },\n    {\n      \"name\": \"RGBW Strobe\",\n      \"shortName\": \"RGBWstrobe\",\n      \"rdmPersonalityIndex\": 7,\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\"\n      ]\n    },\n    {\n      \"name\": \"Advanced RGB Strobe 1-Pixel\",\n      \"shortName\": \"RGBstrobe1pix\",\n      \"rdmPersonalityIndex\": 8,\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        \"1-Pixel Red\",\n        \"1-Pixel Green\",\n        \"1-Pixel Blue\"\n      ]\n    },\n    {\n      \"name\": \"Advanced RGB Strobe 2V-Pixel\",\n      \"shortName\": \"RGBstrobe2pixV\",\n      \"rdmPersonalityIndex\": 9,\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        \"2V-Pixel 1 Red\",\n        \"2V-Pixel 1 Green\",\n        \"2V-Pixel 1 Blue\",\n        \"2V-Pixel 2 Red\",\n        \"2V-Pixel 2 Green\",\n        \"2V-Pixel 2 Blue\"\n      ]\n    },\n    {\n      \"name\": \"Advanced RGB Strobe 2H-Pixel\",\n      \"shortName\": \"RGBstrobe2pixH\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        \"2H-Pixel 1 Red\",\n        \"2H-Pixel 1 Green\",\n        \"2H-Pixel 1 Blue\",\n        \"2H-Pixel 2 Red\",\n        \"2H-Pixel 2 Green\",\n        \"2H-Pixel 2 Blue\"\n      ]\n    },\n    {\n      \"name\": \"Advanced RGB Strobe 3-Pixel\",\n      \"shortName\": \"RGBstrobe3pix\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"3-Pixel 1\",\n            \"3-Pixel 2\",\n            \"3-Pixel 3\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGB Strobe 4-Pixel\",\n      \"shortName\": \"RGBstrobe4pix\",\n      \"rdmPersonalityIndex\": 10,\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"4-Pixel 1\",\n            \"4-Pixel 2\",\n            \"4-Pixel 3\",\n            \"4-Pixel 4\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGB Strobe 6V-Pixel\",\n      \"shortName\": \"RGBstrobe6pixV\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"6V-Pixel 1\",\n            \"6V-Pixel 2\",\n            \"6V-Pixel 3\",\n            \"6V-Pixel 4\",\n            \"6V-Pixel 5\",\n            \"6V-Pixel 6\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGB Strobe 6H-Pixel\",\n      \"shortName\": \"RGBstrobe6pixH\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"6H-Pixel 1\",\n            \"6H-Pixel 2\",\n            \"6H-Pixel 3\",\n            \"6H-Pixel 4\",\n            \"6H-Pixel 5\",\n            \"6H-Pixel 6\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGB Strobe 12-Pixel\",\n      \"shortName\": \"RGBstrobe12pix\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"12-Pixel 1\",\n            \"12-Pixel 2\",\n            \"12-Pixel 3\",\n            \"12-Pixel 4\",\n            \"12-Pixel 5\",\n            \"12-Pixel 6\",\n            \"12-Pixel 7\",\n            \"12-Pixel 8\",\n            \"12-Pixel 9\",\n            \"12-Pixel 10\",\n            \"12-Pixel 11\",\n            \"12-Pixel 12\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGBW Strobe 1-Pixel\",\n      \"shortName\": \"RGBWstrobe1pix\",\n      \"rdmPersonalityIndex\": 11,\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        \"1-Pixel Red\",\n        \"1-Pixel Green\",\n        \"1-Pixel Blue\",\n        \"1-Pixel White\"\n      ]\n    },\n    {\n      \"name\": \"Advanced RGBW Strobe 2V-Pixel\",\n      \"shortName\": \"RGBWstrobe2pixV\",\n      \"rdmPersonalityIndex\": 12,\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        \"2V-Pixel 1 Red\",\n        \"2V-Pixel 1 Green\",\n        \"2V-Pixel 1 Blue\",\n        \"2V-Pixel 1 White\",\n        \"2V-Pixel 2 Red\",\n        \"2V-Pixel 2 Green\",\n        \"2V-Pixel 2 Blue\",\n        \"2V-Pixel 2 White\"\n      ]\n    },\n    {\n      \"name\": \"Advanced RGBW Strobe 2H-Pixel\",\n      \"shortName\": \"RGBWstrobe2pixH\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        \"2H-Pixel 1 Red\",\n        \"2H-Pixel 1 Green\",\n        \"2H-Pixel 1 Blue\",\n        \"2H-Pixel 1 White\",\n        \"2H-Pixel 2 Red\",\n        \"2H-Pixel 2 Green\",\n        \"2H-Pixel 2 Blue\",\n        \"2H-Pixel 2 White\"\n      ]\n    },\n    {\n      \"name\": \"Advanced RGBW Strobe 3-Pixel\",\n      \"shortName\": \"RGBWstrobe3pix\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"3-Pixel 1\",\n            \"3-Pixel 2\",\n            \"3-Pixel 3\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGBW Strobe 4-Pixel\",\n      \"shortName\": \"RGBWstrobe4pix\",\n      \"rdmPersonalityIndex\": 13,\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"4-Pixel 1\",\n            \"4-Pixel 2\",\n            \"4-Pixel 3\",\n            \"4-Pixel 4\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGBW Strobe 6V-Pixel\",\n      \"shortName\": \"RGBWstrobe6pixV\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"6V-Pixel 1\",\n            \"6V-Pixel 2\",\n            \"6V-Pixel 3\",\n            \"6V-Pixel 4\",\n            \"6V-Pixel 5\",\n            \"6V-Pixel 6\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGBW Strobe 6H-Pixel\",\n      \"shortName\": \"RGBWstrobe6pixH\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"6H-Pixel 1\",\n            \"6H-Pixel 2\",\n            \"6H-Pixel 3\",\n            \"6H-Pixel 4\",\n            \"6H-Pixel 5\",\n            \"6H-Pixel 6\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"Advanced RGBW Strobe 12-Pixel\",\n      \"shortName\": \"RGBWstrobe12pix\",\n      \"channels\": [\n        \"Red Strobe\",\n        \"Green Strobe\",\n        \"Blue Strobe\",\n        \"White Strobe\",\n        \"Flash intensity\",\n        \"Flash duration\",\n        \"Flash rate\",\n        \"Flash effects\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"12-Pixel 1\",\n            \"12-Pixel 2\",\n            \"12-Pixel 3\",\n            \"12-Pixel 4\",\n            \"12-Pixel 5\",\n            \"12-Pixel 6\",\n            \"12-Pixel 7\",\n            \"12-Pixel 8\",\n            \"12-Pixel 9\",\n            \"12-Pixel 10\",\n            \"12-Pixel 11\",\n            \"12-Pixel 12\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"$pixelKey Red\",\n            \"$pixelKey Green\",\n            \"$pixelKey Blue\",\n            \"$pixelKey White\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/tomshine/3-led-par-light-rgbuv.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"3 LED Par Light RGBUV\",\n  \"shortName\": \"TomShine3LEDParRGBUV\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Paul Rogalski\"],\n    \"createDate\": \"2024-10-09\",\n    \"lastModifyDate\": \"2024-10-09\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://forums.pioneerdj.com/hc/user_images/rB7cJ4VXCxgGGiFUXQsAyg.jpeg\"\n    ],\n    \"productPage\": [\n      \"https://www.tomshine.com/p-l1582us.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [140, 140, 140],\n    \"weight\": 0.595,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3x 4W LED (RGBUV)\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [40, 40]\n    }\n  },\n  \"availableChannels\": {\n    \"No Function\": {\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Special Functions\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Speed\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Static Color\",\n          \"switchChannels\": {\n            \"Speed\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"switchChannels\": {\n            \"Speed\": \"Strobe Speed\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#008000\"]\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#800080\"]\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green\",\n          \"colors\": [\"#ff0000\", \"#008000\"]\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue\",\n          \"colors\": [\"#ff0000\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + UV\",\n          \"colors\": [\"#ff0000\", \"#800080\"]\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue\",\n          \"colors\": [\"#008000\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [150, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + UV\",\n          \"colors\": [\"#008000\", \"#800080\"]\n        },\n        {\n          \"dmxRange\": [160, 169],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue + UV\",\n          \"colors\": [\"#0000ff\", \"#800080\"]\n        },\n        {\n          \"dmxRange\": [170, 179],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + UV\",\n          \"colors\": [\"#ff0000\", \"#008000\", \"#800080\"]\n        },\n        {\n          \"dmxRange\": [180, 189],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Blue + UV\",\n          \"colors\": [\"#ff0000\", \"#0000ff\", \"#800080\"]\n        },\n        {\n          \"dmxRange\": [190, 199],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green + Blue + UV\",\n          \"colors\": [\"#008000\", \"#0000ff\", \"#800080\"]\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue\",\n          \"colors\": [\"#ff0000\", \"#008000\", \"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [210, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red + Green + Blue + UV\",\n          \"colors\": [\"#ff0000\", \"#008000\", \"#0000ff\", \"#800080\"]\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Strobe Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"StrobeSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"UV\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Special Functions\",\n        \"Color Presets\",\n        \"Speed\",\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/tomshine/80w-mini-gobo-moving-head.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"80W Mini Gobo Moving Head\",\n  \"shortName\": \"Mini Gobo MH\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"xMGFamerPlex\", \"FloEdelmann\"],\n    \"createDate\": \"2026-01-30\",\n    \"lastModifyDate\": \"2026-01-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://m.media-amazon.com/images/I/91yl8pOcIML.pdf\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=e8dZjDtsZp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [200, 260, 147],\n    \"weight\": 3.1,\n    \"power\": 80,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Cyan\",\n          \"colors\": [\"#00fff0\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Pink\",\n          \"colors\": [\"#ff00aa\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/double-lines-star\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/square-arrows\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/circular-drops\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/5-pointed-star\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/stones\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/crescent\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/caro-flower\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"1deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"230deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\",\n          \"helpWanted\": \"At which DMX values is strobe disabled?\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 24],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [25, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8.5\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [64, 71],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 1,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [72, 79],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [80, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 95],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [96, 103],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [104, 111],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [112, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [120, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Sound Mode\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 127],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Random moving with colors and gobos\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    },\n    \"Function\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 69],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Pan/Tilt movement\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Color Wheel movement\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Blackout during Gobo Wheel movement\"\n        },\n        {\n          \"dmxRange\": [120, 199],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [200, 209],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [210, 249],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Voice control function\"\n        }\n      ]\n    },\n    \"Dimmer Curve\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 20],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Standard\"\n        },\n        {\n          \"dmxRange\": [21, 40],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Stage\"\n        },\n        {\n          \"dmxRange\": [41, 60],\n          \"type\": \"Maintenance\",\n          \"comment\": \"TV\"\n        },\n        {\n          \"dmxRange\": [61, 80],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Architectural\"\n        },\n        {\n          \"dmxRange\": [81, 100],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Theater\"\n        },\n        {\n          \"dmxRange\": [101, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Default\"\n        }\n      ]\n    },\n    \"Strobe (2022)\": {\n      \"name\": \"Strobe\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [16, 131],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        },\n        {\n          \"dmxRange\": [132, 139],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [140, 181],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [182, 189],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [190, 231],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [232, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [240, 247],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Sound Mode\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"9-channel (2022)\",\n      \"shortName\": \"9ch (2022)\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Strobe (2022)\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Function\",\n        \"Dimmer Curve\"\n      ]\n    },\n    {\n      \"name\": \"11-channel (2022)\",\n      \"shortName\": \"11ch (2022)\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Strobe (2022)\",\n        \"Dimmer\",\n        \"Pan/Tilt Speed\",\n        \"Function\",\n        \"Dimmer Curve\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/uking/b117-par-can-4in1-rgbw-18-leds.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"B117 Par Can 4in1 RGBW 18 LEDs\",\n  \"shortName\": \"b117-par-can\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\", \"Flo Edelmann\"],\n    \"createDate\": \"2022-03-13\",\n    \"lastModifyDate\": \"2024-01-10\"\n  },\n  \"comment\": \"This is an unbranded fixture bought online, but the appearance and user manual match the UKing B117 closely.\\n\\nThe B117 webpage isn't even internally consistent, so I've done the best I could here.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.uking-online.com/wp-content/uploads/2020/10/ZQ-B117.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.uking-online.com/product/b117-par-can-4in1-rgbw-18-leds/\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [225, 225, 115],\n    \"weight\": 3.2,\n    \"power\": 200,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Effect\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 50],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed\": \"No Function\"\n          }\n        },\n        {\n          \"dmxRange\": [51, 100],\n          \"type\": \"Effect\",\n          \"effectName\": \"Color Presets\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed\": \"Color Presets\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 150],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"Effect\",\n          \"effectName\": \"Colors Pulse Change\",\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-Active\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Color Presets / Effect Speed\": \"Effect Speed\"\n          }\n        }\n      ]\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 32],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [33, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"No Function\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Strobe\",\n        \"Effect\",\n        \"Color Presets / Effect Speed\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/uking/mini-led-spot-25w.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Mini LED Spot 25W\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2020-04-18\",\n    \"lastModifyDate\": \"2020-04-18\"\n  },\n  \"physical\": {\n    \"dimensions\": [178, 250, 178],\n    \"weight\": 2.8,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"10W RGBW LED\"\n    }\n  },\n  \"wheels\": {\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"220deg\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 1\",\n          \"helpWanted\": \"Which colors can be selected at which DMX values?\"\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 2\"\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 3\"\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 4\"\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 5\"\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 6\"\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 7\"\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 8\"\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 9\"\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 10\"\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 11\"\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 12\"\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 13\"\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Color 14\"\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [10, 19],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [20, 29],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [30, 39],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [40, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [50, 59],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [60, 69],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [70, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [80, 89],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [90, 99],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [100, 109],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [110, 119],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [120, 129],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [130, 139],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [140, 149],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [150, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 30],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [31, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [61, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [91, 120],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [121, 150],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 4\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [151, 180],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Program 1\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [181, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Program 2\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"System reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"10-channel\",\n      \"shortName\": \"10ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Gobo Wheel\",\n        \"Auto Programs\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Color Macros\",\n        \"Gobo Wheel\",\n        \"Auto Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/uking/par-light-b262.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Par Light B262\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Jason dinAlt\"],\n    \"createDate\": \"2020-11-27\",\n    \"lastModifyDate\": \"2020-11-27\"\n  },\n  \"comment\": \"This light appears to be identical to the \\\"LUNSY DJ Par Lights.\\\"\\n\\nSee \\\"other\\\" links for the LUNSY products and reviews.\\n\\nI was unable to find an online copy of the manual -- the manual link is someone's photo of a U'King manual, different model, which appears to have the same information as the one which came with the lights.\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.uking-online.com/wp-content/uploads/2020/10/ZQ-B262.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.uking-online.com/product/par-can-b262-36w-36led-rgb-par-light-uking/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=P78wPS66ASM\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 180, 100],\n    \"weight\": 0.48,\n    \"power\": 36,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"availableChannels\": {\n    \"Master Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Manual mode\",\n          \"switchChannels\": {\n            \"Hue Selection / Speed\": \"Hue Selection\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hue Select\",\n          \"switchChannels\": {\n            \"Hue Selection / Speed\": \"Hue Selection\"\n          }\n        },\n        {\n          \"dmxRange\": [61, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hue Shift\",\n          \"switchChannels\": {\n            \"Hue Selection / Speed\": \"Hue Shift Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [111, 160],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hue Pulse Transform\",\n          \"comment\": \"Hue fades in and out, then shifts\",\n          \"switchChannels\": {\n            \"Hue Selection / Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [161, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Hue Transition\",\n          \"comment\": \"Hue transitions to next in sequence\",\n          \"switchChannels\": {\n            \"Hue Selection / Speed\": \"Effect Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Hue Selection / Speed\": \"Effect Speed\"\n          }\n        }\n      ]\n    },\n    \"Hue Selection\": {\n      \"capability\": {\n        \"type\": \"Generic\",\n        \"comment\": \"Hue selection\"\n      }\n    },\n    \"Hue Shift Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Master Dimmer\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Strobe\",\n        \"Mode\",\n        \"Hue Selection / Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/uking/zq-b20-mini-spider-light.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ZQ-B20 Mini Spider Light\",\n  \"shortName\": \"ZQ-B20-MiniSpider\",\n  \"categories\": [\"Effect\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Ryan Goodwin\"],\n    \"createDate\": \"2023-04-24\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"productPage\": [\n      \"https://www.uking-online.com/product/uking-zq-b20-mini-60w-spider-light/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=4KL1MdtnQ34\"\n    ],\n    \"manual\": [\n      \"https://www.uking-online.com/wp-content/uploads/2020/10/ZQ-B20.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [280, 150, 130],\n    \"weight\": 1.99,\n    \"power\": 80,\n    \"powerConnectors\": {\n      \"IEC C13\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [3, 3]\n    }\n  },\n  \"availableChannels\": {\n    \"Tilt 1\": {\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"135deg\"\n      }\n    },\n    \"Tilt 2\": {\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"135deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 17],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 1\"\n        },\n        {\n          \"dmxRange\": [18, 27],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 2\"\n        },\n        {\n          \"dmxRange\": [28, 37],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 3\"\n        },\n        {\n          \"dmxRange\": [38, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 4\"\n        },\n        {\n          \"dmxRange\": [48, 57],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 5\"\n        },\n        {\n          \"dmxRange\": [58, 67],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 6\"\n        },\n        {\n          \"dmxRange\": [68, 77],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 7\"\n        },\n        {\n          \"dmxRange\": [78, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 8\"\n        },\n        {\n          \"dmxRange\": [88, 97],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 9\"\n        },\n        {\n          \"dmxRange\": [98, 107],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 10\"\n        },\n        {\n          \"dmxRange\": [108, 117],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 11\"\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 12\"\n        },\n        {\n          \"dmxRange\": [128, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 13\"\n        },\n        {\n          \"dmxRange\": [137, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 14\"\n        },\n        {\n          \"dmxRange\": [147, 156],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 15\"\n        },\n        {\n          \"dmxRange\": [157, 166],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 16\"\n        },\n        {\n          \"dmxRange\": [167, 176],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 17\"\n        },\n        {\n          \"dmxRange\": [177, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 18\"\n        },\n        {\n          \"dmxRange\": [187, 196],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 19\"\n        },\n        {\n          \"dmxRange\": [197, 206],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 20\"\n        },\n        {\n          \"dmxRange\": [207, 216],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 21\"\n        },\n        {\n          \"dmxRange\": [217, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 22\"\n        },\n        {\n          \"dmxRange\": [227, 236],\n          \"type\": \"Effect\",\n          \"effectName\": \"Effect 23\"\n        },\n        {\n          \"dmxRange\": [237, 246],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Mode\"\n        },\n        {\n          \"dmxRange\": [247, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Active Mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Effect Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 240],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Maintenance\",\n          \"hold\": \"5s\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    },\n    \"Red 1\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green 1\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue 1\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White 1\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Red 2\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green 2\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue 2\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White 2\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Tilt 1\",\n        \"Tilt 2\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Effect\",\n        \"Effect Speed\",\n        \"Reset\"\n      ]\n    },\n    {\n      \"name\": \"15-channel\",\n      \"shortName\": \"15ch\",\n      \"channels\": [\n        \"Tilt 1\",\n        \"Tilt 2\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red 1\",\n        \"Green 1\",\n        \"Blue 1\",\n        \"White 1\",\n        \"Red 2\",\n        \"Green 2\",\n        \"Blue 2\",\n        \"White 2\",\n        \"Effect\",\n        \"Effect Speed\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/ultratec/radiance-hazer.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Radiance Hazer\",\n  \"shortName\": \"radiance-hazer\",\n  \"categories\": [\"Hazer\"],\n  \"meta\": {\n    \"authors\": [\"Ken Harris\"],\n    \"createDate\": \"2022-02-26\",\n    \"lastModifyDate\": \"2022-02-26\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://gmbh.ultratecfx.com/docs/default-source/downloads-radiance-hazer/radiance-haze-manual-2020.pdf?sfvrsn=2\"\n    ],\n    \"productPage\": [\n      \"https://ultratecfx.com/atmospherics/products-catalog/radiance-hazer/\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=yOKOLkTNOuw\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [279, 180, 419],\n    \"weight\": 13,\n    \"power\": 500,\n    \"DMXconnector\": \"5-pin\"\n  },\n  \"availableChannels\": {\n    \"Haze\": {\n      \"capability\": {\n        \"type\": \"Fog\",\n        \"fogType\": \"Haze\",\n        \"fogOutputStart\": \"0%\",\n        \"fogOutputEnd\": \"100%\"\n      }\n    },\n    \"Fan\": {\n      \"capability\": {\n        \"type\": \"Rotation\",\n        \"speedStart\": \"slow CW\",\n        \"speedEnd\": \"fast CW\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Haze\",\n        \"Fan\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/bat-par-6-rgbuv.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BAT.PAR 6 RGBUV\",\n  \"shortName\": \"VaryBat6RGBUV\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Aurelien W\"],\n    \"createDate\": \"2019-06-08\",\n    \"lastModifyDate\": \"2019-06-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/385475_c_385435_385475_r2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/varytec_bat.par_6_rgbuv.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [254, 250, 129.65],\n    \"weight\": 1.9,\n    \"power\": 48,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"6x 8W RGBUV LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"comment\": \"Color macro 1…51\",\n        \"helpWanted\": \"At which DMX values can which color macros be selected?\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode 2\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0%\",\n        \"speedEnd\": \"100%\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"UV\",\n        \"Programs\",\n        \"Strobe / Program Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/bat-par-6-rgbwa.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"BAT.PAR 6 RGBWA\",\n  \"shortName\": \"VaryBat6RGBWA\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Aurelien W\"],\n    \"createDate\": \"2019-06-08\",\n    \"lastModifyDate\": \"2019-06-08\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/385435_c_385435_385475_r2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/varytec_bat_par_6_rgbwa.htm\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [254, 250, 129.65],\n    \"weight\": 1.9,\n    \"power\": 48,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"6x 8W RGBWA LEDs\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [25, 25]\n    }\n  },\n  \"availableChannels\": {\n    \"Color Macros\": {\n      \"capability\": {\n        \"type\": \"ColorPreset\",\n        \"comment\": \"Color macro 1…51\",\n        \"helpWanted\": \"At which DMX values can which color macros be selected?\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"Programs\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 1\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 2\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 3\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 4\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 5\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 6\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 7\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 8\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [144, 159],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 9\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 175],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 10\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 11\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 12\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [208, 223],\n          \"type\": \"Effect\",\n          \"effectName\": \"Program 13\",\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [224, 239],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode 1\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound mode 2\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"0%\",\n        \"speedEnd\": \"100%\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Color Macros\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\"\n      ]\n    },\n    {\n      \"name\": \"7-channel\",\n      \"shortName\": \"7ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Intensity\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"Programs\",\n        \"Strobe / Program Speed / Sound Sensitivity\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/easy-move-xs-hp-wash-7x8w-rgbw.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \" Easy Move XS HP Wash 7x8W RGBW\",\n  \"shortName\": \"Mini Wash\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"AL_DAVE\", \"Flo Edelmann\"],\n    \"createDate\": \"2021-06-17\",\n    \"lastModifyDate\": \"2021-06-17\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/301511_c_301511_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/varytec_easy_move_xs_hp_wash_7x8w_rgbw.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=xYcylXUi5EA\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [177, 238, 176],\n    \"weight\": 5,\n    \"power\": 75,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"180deg\"\n      }\n    },\n    \"Dimmer & Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [8, 134],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"0%\",\n          \"brightnessEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [135, 239],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"40Hz\"\n        },\n        {\n          \"dmxRange\": [240, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"highlightValue\": 255,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Presets\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [16, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\"\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [80, 127],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\"\n        },\n        {\n          \"dmxRange\": [128, 143],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [144, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Violet\"\n        },\n        {\n          \"dmxRange\": [176, 191],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Light blue\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [224, 237],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [238, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 3],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [4, 203],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Programs\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Programs\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 254],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Reset\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer & Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Pan/Tilt Speed\"\n      ]\n    },\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer & Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Presets\",\n        \"Auto Programs\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/giga-bar-frost-pix-8-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Giga Bar Frost Pix 8 RGB\",\n  \"categories\": [\"Pixel Bar\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Luke Nelson\"],\n    \"createDate\": \"2022-10-12\",\n    \"lastModifyDate\": \"2022-10-12\",\n    \"importPlugin\": {\n      \"plugin\": \"qlcplus_4.12.1\",\n      \"date\": \"2022-10-12\",\n      \"comment\": \"created by Q Light Controller Plus (version 4.12.6)\"\n    }\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_460683_460684_v2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/gb/varytec_giga_bar_frost_pix_8_rgb.htm\"\n    ],\n    \"video\": [\"https://www.youtube.com/watch?v=PixpS09Mc-I\"]\n  },\n  \"physical\": {\n    \"dimensions\": [1020, 80, 65],\n    \"weight\": 1.5,\n    \"power\": 25,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [30, 30]\n    }\n  },\n  \"matrix\": {\n    \"pixelCount\": [8, 1, 1],\n    \"pixelGroups\": {\n      \"Master\": \"all\"\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ShutterStrobe\",\n        \"shutterEffect\": \"Strobe\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\",\n        \"helpWanted\": \"At which DMX values is strobe disabled? When is the lamp constantly on/off?\"\n      }\n    },\n    \"Multi-function\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"No function\"\n          }\n        },\n        {\n          \"dmxRange\": [8, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Constant uni-colored pattern in red\",\n          \"colors\": [\"#ff2600\"],\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"No function\"\n          }\n        },\n        {\n          \"dmxRange\": [16, 23],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Constant uni-colored pattern in red and green\",\n          \"helpWanted\": \"Are these patterns uni-colored (yellow in this case) or multi-colored?\",\n          \"colors\": [\"#ff2600\", \"#00f900\"],\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"No function\"\n          }\n        },\n        {\n          \"dmxRange\": [24, 31],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Constant uni-colored pattern in green\",\n          \"colors\": [\"#00f900\"],\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"No function\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 39],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Constant uni-colored pattern in blue and green\",\n          \"colors\": [\"#0433ff\", \"#00f900\"],\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"No function\"\n          }\n        },\n        {\n          \"dmxRange\": [40, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Constant uni-colored pattern in blue\",\n          \"colors\": [\"#0433ff\"],\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"No function\"\n          }\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Constant uni-colored pattern in blue and red\",\n          \"colors\": [\"#0433ff\", \"#ff2600\"],\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"No function\"\n          }\n        },\n        {\n          \"dmxRange\": [56, 63],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Constant uni-colored pattern in red, green and blue\",\n          \"colors\": [\"#ffffff\"],\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"No function\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 231],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in automatic show programs\",\n          \"helpWanted\": \"At which DMX values do the effects change?\",\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [232, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled show\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Speed / Sensitivity\": \"Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Speed\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sensitivity\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"No function\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"NoFunction\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\"\n      ]\n    },\n    {\n      \"name\": \"5-channel\",\n      \"shortName\": \"5ch\",\n      \"channels\": [\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Multi-function\",\n        \"Speed / Sensitivity\"\n      ]\n    },\n    {\n      \"name\": \"24-channel\",\n      \"shortName\": \"24ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelXYZ\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/giga-bar-hex-3.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Giga Bar HEX 3\",\n  \"categories\": [\"Color Changer\", \"Strobe\", \"Effect\"],\n  \"meta\": {\n    \"authors\": [\"Erik Pade\", \"Flo Edelmann\", \"Chemin Rouge Evenements\", \"Luke Nelson\"],\n    \"createDate\": \"2021-09-19\",\n    \"lastModifyDate\": \"2023-02-28\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/472654_c_472654_472655_r2_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/varytec_giga_bar_hex_3.htm\"\n    ],\n    \"video\": [\n      \"https://video2.thomann.de/vidiot/02591c1c/video_i8849p10_yd59vqpa.mp4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [360, 150, 64],\n    \"weight\": 1.2,\n    \"power\": 36,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3× 12W RGBAWUV LED\"\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Amber\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Amber\"\n      }\n    },\n    \"UV\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"UV\"\n      }\n    },\n    \"Intensity\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [101, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Auto Program Selection\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [11, 100],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [101, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Program Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Program Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Program Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capability\": {\n        \"type\": \"SoundSensitivity\",\n        \"soundSensitivityStart\": \"low\",\n        \"soundSensitivityEnd\": \"high\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 14],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [15, 22],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [23, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [41, 47],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pure White\",\n          \"colors\": [\"#fffffc\"]\n        },\n        {\n          \"dmxRange\": [48, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Amber\",\n          \"colors\": [\"#ffbf00\"]\n        },\n        {\n          \"dmxRange\": [56, 62],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"UV\",\n          \"colors\": [\"#8800ff\"]\n        },\n        {\n          \"dmxRange\": [63, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [71, 78],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Fuchsia\",\n          \"colors\": [\"#b83dae\"]\n        },\n        {\n          \"dmxRange\": [79, 86],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Pink\",\n          \"colors\": [\"#ffc0cb\"]\n        },\n        {\n          \"dmxRange\": [87, 94],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"dmxRange\": [95, 102],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Purple\",\n          \"colors\": [\"#8e44c6\"]\n        },\n        {\n          \"dmxRange\": [103, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [111, 118],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mint\",\n          \"colors\": [\"#aefac6\"]\n        },\n        {\n          \"dmxRange\": [119, 126],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime\",\n          \"colors\": [\"#bfff00\"]\n        },\n        {\n          \"dmxRange\": [127, 134],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#73abeb\"]\n        },\n        {\n          \"dmxRange\": [135, 142],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Terra Cotta\",\n          \"colors\": [\"#c9643b\"]\n        },\n        {\n          \"dmxRange\": [143, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Turquoise\",\n          \"colors\": [\"#33d79a\"]\n        },\n        {\n          \"dmxRange\": [151, 158],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Tan\",\n          \"colors\": [\"#d2b48c\"]\n        },\n        {\n          \"dmxRange\": [159, 166],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gold\",\n          \"colors\": [\"#ffd700\"]\n        },\n        {\n          \"dmxRange\": [167, 174],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [175, 182],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Redviolet\",\n          \"colors\": [\"#b62e46\"]\n        },\n        {\n          \"dmxRange\": [183, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Coral\",\n          \"colors\": [\"#ff7c7c\"]\n        },\n        {\n          \"dmxRange\": [191, 198],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Aqua\",\n          \"colors\": [\"#13eac9\"]\n        },\n        {\n          \"dmxRange\": [199, 206],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Aquamarine\",\n          \"colors\": [\"#7fffd4\"]\n        },\n        {\n          \"dmxRange\": [207, 214],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Emerald\",\n          \"colors\": [\"#50c878\"]\n        },\n        {\n          \"dmxRange\": [215, 222],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lavender\",\n          \"colors\": [\"#cfb5e2\"]\n        },\n        {\n          \"dmxRange\": [223, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ice\",\n          \"colors\": [\"#d6fffa\"]\n        },\n        {\n          \"dmxRange\": [231, 238],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Rosepink\",\n          \"colors\": [\"#f97a8c\"]\n        },\n        {\n          \"dmxRange\": [239, 246],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palegreen\",\n          \"colors\": [\"#abeca2\"]\n        },\n        {\n          \"dmxRange\": [247, 254],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Palepink\",\n          \"colors\": [\"#e8c3d4\"]\n        },\n        {\n          \"dmxRange\": [255, 255],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Babyblue\",\n          \"colors\": [\"#9ed7fc\"]\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    },\n    {\n      \"name\": \"4-channel\",\n      \"shortName\": \"4ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Auto Programs\"\n      ]\n    },\n    {\n      \"name\": \"11-channel\",\n      \"shortName\": \"11ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Amber\",\n        \"UV\",\n        \"Intensity\",\n        \"Strobe\",\n        \"Auto Program Selection\",\n        \"Program Speed / Sound Sensitivity\",\n        \"Color Macros\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/hero-spot-230.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hero Spot 230\",\n  \"shortName\": \"Hero Spot 230\",\n  \"categories\": [\"Moving Head\"],\n  \"meta\": {\n    \"authors\": [\"Leon Dietrich\", \"Flo Edelmann\"],\n    \"createDate\": \"2026-02-26\",\n    \"lastModifyDate\": \"2026-02-26\"\n  },\n  \"comment\": \"Theatrical Spotlight\",\n  \"links\": {\n    \"manual\": [\n      \"https://www.manualslib.com/manual/2109134/Varytec-Hero-Spot-230.html\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.ae/varytec_hero_spot_230.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=7P86HXiNGU4\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [303, 457, 188],\n    \"weight\": 12.7,\n    \"power\": 250,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"3000K\",\n          \"colorTemperature\": \"3000K\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Dark Blue\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Light Blue\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/5-fold-swirl-inverted\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/rays\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/tiny-stars\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/shards\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/rose-petal-abstract\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/pointed-grid\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/comets\"\n        }\n      ]\n    },\n    \"Rotatable Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/quarter-mark\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/edge-touching-circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/4-line-arranged-dots\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/triangle-outline\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/1-vertical-bar\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/32-circles\"\n        },\n        {\n          \"type\": \"Gobo\",\n          \"resource\": \"gobos/circle-outline\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"260deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [81, 140],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Automatic Effects\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 47],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 1\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [48, 87],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 3\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 167],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 4\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [168, 207],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 5\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [208, 247],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 6\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [248, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music Control\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Pan/Tilt Automatics\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Use Channel 1 & 2\"\n        },\n        {\n          \"dmxRange\": [8, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Automatic Program 1\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [33, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Automatic Program 2\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [59, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Automatic Program 3\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [85, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Automatic Program 4\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [111, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Automatic Program 5\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [137, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Automatic Program 6\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [163, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Automatic Program 7\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [189, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pan/Tilt Automatic Program 8\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [215, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Music based Pan/Tilt automatic mode\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 4],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [5, 13],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1.5\n        },\n        {\n          \"dmxRange\": [14, 22],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [23, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2.5\n        },\n        {\n          \"dmxRange\": [32, 40],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [41, 49],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3.5\n        },\n        {\n          \"dmxRange\": [50, 58],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [59, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4.5\n        },\n        {\n          \"dmxRange\": [68, 76],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [77, 85],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5.5\n        },\n        {\n          \"dmxRange\": [86, 94],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [95, 103],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6.5\n        },\n        {\n          \"dmxRange\": [104, 112],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [113, 121],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7.5\n        },\n        {\n          \"dmxRange\": [122, 130],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [131, 139],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [140, 195],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [196, 199],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [200, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [28, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [38, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [48, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [58, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [68, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [78, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 97],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [98, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [108, 117],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [138, 147],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [148, 199],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Rotatable Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [8, 17],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [18, 27],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [28, 37],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [38, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [48, 57],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [58, 67],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [68, 77],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [78, 87],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 2,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [88, 97],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 3,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [98, 107],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 4,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [108, 117],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 5,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [118, 127],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 6,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 7,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [138, 147],\n          \"type\": \"WheelShake\",\n          \"slotNumber\": 8,\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [148, 199],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [200, 203],\n          \"type\": \"WheelRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotatable Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 47],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotatable Gobo Wheel\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"359deg\"\n        },\n        {\n          \"dmxRange\": [48, 127],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotatable Gobo Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [128, 137],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotatable Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [138, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Rotatable Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Prism\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\"\n        },\n        {\n          \"dmxRange\": [8, 99],\n          \"type\": \"Prism\",\n          \"comment\": \"Circular\"\n        },\n        {\n          \"dmxRange\": [100, 130],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Open\"\n        },\n        {\n          \"dmxRange\": [131, 255],\n          \"type\": \"Prism\",\n          \"comment\": \"Linear\"\n        }\n      ]\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [8, 129],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [130, 133],\n          \"type\": \"PrismRotation\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [134, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 189],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [190, 210],\n          \"type\": \"Maintenance\",\n          \"hold\": \"10s\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Automatic Effects\",\n        \"Pan/Tilt Automatics\"\n      ]\n    },\n    {\n      \"name\": \"18-channel\",\n      \"shortName\": \"18ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Rotatable Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Focus\",\n        \"Zoom\",\n        \"Prism\",\n        \"Prism Rotation\",\n        \"Automatic Effects\",\n        \"Pan/Tilt Automatics\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/hero-wash-340fx-rgbw-zoom.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hero Wash 340FX RGBW Zoom\",\n  \"shortName\": \"Hero Wash 340FX\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Kai Otte\", \"Ryan Goodwin\"],\n    \"createDate\": \"2021-07-09\",\n    \"lastModifyDate\": \"2023-07-12\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_449223_v3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/gb/varytec_hero_wash_340fx_rgbw_zoom.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Jzb-RsAqWRc\"\n    ],\n    \"other\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/misc/449223_photometric_data.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [255, 187, 368],\n    \"weight\": 6.1,\n    \"power\": 134,\n    \"powerConnectors\": {\n      \"powerCON\": \"input and output\"\n    },\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3× 40W RGBW LED\",\n      \"colorTemperature\": 6461\n    },\n    \"lens\": {\n      \"degreesMinMax\": [4, 45]\n    }\n  },\n  \"wheels\": {\n    \"Beam Split Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Open\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"540deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"dmxValueResolution\": \"8bit\",\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"210deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Shutter / Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [10, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red, White\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green, White\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue, White\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red, Green\"\n        },\n        {\n          \"dmxRange\": [91, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green, Blue\"\n        },\n        {\n          \"dmxRange\": [101, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red, Blue\"\n        },\n        {\n          \"dmxRange\": [111, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red, Green, Blue\"\n        },\n        {\n          \"dmxRange\": [121, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green, Blue, White\"\n        },\n        {\n          \"dmxRange\": [131, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red, Blue, White\"\n        },\n        {\n          \"dmxRange\": [141, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red, Green, Blue, White\"\n        },\n        {\n          \"dmxRange\": [151, 200],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Beam Split Effect\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 100],\n          \"type\": \"WheelSlot\",\n          \"wheel\": \"Beam Split Wheel\",\n          \"slotNumberStart\": 1,\n          \"slotNumberEnd\": 1.5\n        },\n        {\n          \"dmxRange\": [101, 133],\n          \"type\": \"WheelShake\",\n          \"wheel\": \"Beam Split Wheel\",\n          \"shakeSpeedStart\": \"slow\",\n          \"shakeSpeedEnd\": \"fast\",\n          \"comment\": \"Yo-Yo Effect\"\n        },\n        {\n          \"dmxRange\": [134, 194],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Beam Split Wheel\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [195, 255],\n          \"type\": \"WheelRotation\",\n          \"wheel\": \"Beam Split Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Auto Programs\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [11, 20],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed automatic show 1\"\n        },\n        {\n          \"dmxRange\": [21, 30],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed automatic show 2\"\n        },\n        {\n          \"dmxRange\": [31, 40],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed automatic show 3\"\n        },\n        {\n          \"dmxRange\": [41, 50],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed automatic show 4\"\n        },\n        {\n          \"dmxRange\": [51, 60],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed automatic show 5\"\n        },\n        {\n          \"dmxRange\": [61, 70],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed automatic show 6\"\n        },\n        {\n          \"dmxRange\": [71, 80],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed automatic show 7\"\n        },\n        {\n          \"dmxRange\": [81, 90],\n          \"type\": \"Effect\",\n          \"effectName\": \"Preprogrammed automatic show 8\"\n        },\n        {\n          \"dmxRange\": [91, 230],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound control\",\n          \"soundControlled\": true,\n          \"soundSensitivityStart\": \"off\",\n          \"soundSensitivityEnd\": \"high\"\n        },\n        {\n          \"dmxRange\": [231, 240],\n          \"type\": \"Maintenance\",\n          \"hold\": \"3s\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    },\n    \"Color Temperature\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [1, 31],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"2400K\"\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"3600K\"\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"4800K\"\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"6000K\"\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"7200K\"\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"8400K\"\n        },\n        {\n          \"dmxRange\": [192, 223],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"9600K\"\n        },\n        {\n          \"dmxRange\": [224, 255],\n          \"type\": \"ColorTemperature\",\n          \"colorTemperature\": \"10800K\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Color Macros\",\n        \"Zoom\",\n        \"Beam Split Effect\",\n        \"Auto Programs\"\n      ]\n    },\n    {\n      \"name\": \"16-channel\",\n      \"shortName\": \"16ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Shutter / Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"White\",\n        \"Color Temperature\",\n        \"Color Macros\",\n        \"Zoom\",\n        \"Beam Split Effect\",\n        \"Auto Programs\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/hero-wash-640fx.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Hero Wash 640FX\",\n  \"shortName\": \"Hero Wash 640FX\",\n  \"categories\": [\"Moving Head\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Max Kaussow\", \"Leon Dietrich\", \"Flo Edelmann\"],\n    \"createDate\": \"2026-02-02\",\n    \"lastModifyDate\": \"2026-02-02\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/c_477541_r3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/varytec_hero_wash_640fx.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=Tu57rzAXifo\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [303, 425, 188],\n    \"weight\": 11,\n    \"power\": 290,\n    \"DMXconnector\": \"3-pin and 5-pin\",\n    \"bulb\": {\n      \"type\": \"LED\"\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [null,  \"1\",  \"2\", null],\n        [ \"6\", null, null,  \"3\"],\n        [null,  \"5\",  \"4\", null]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"Master\": \"all\",\n      \"Segment 1\": [\"1\", \"4\"],\n      \"Segment 2\": [\"2\", \"5\"],\n      \"Segment 3\": [\"3\", \"6\"]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"White $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"White\"\n      }\n    }\n  },\n  \"availableChannels\": {\n    \"Pan\": {\n      \"fineChannelAliases\": [\"Pan fine\"],\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"720deg\"\n      }\n    },\n    \"Tilt\": {\n      \"fineChannelAliases\": [\"Tilt fine\"],\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0deg\",\n        \"angleEnd\": \"270deg\"\n      }\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [11, 80],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [81, 140],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [141, 200],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Pulse\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [201, 250],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0.5Hz\",\n          \"speedEnd\": \"20Hz\"\n        },\n        {\n          \"dmxRange\": [251, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Zoom\": {\n      \"capability\": {\n        \"type\": \"Zoom\",\n        \"angleStart\": \"narrow\",\n        \"angleEnd\": \"wide\"\n      }\n    },\n    \"Lens Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 99],\n          \"type\": \"Rotation\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"60deg\"\n        },\n        {\n          \"dmxRange\": [100, 133],\n          \"type\": \"Effect\",\n          \"effectName\": \"Pulsating rotatable lens\",\n          \"comment\": \"from small to wide deflection\"\n        },\n        {\n          \"dmxRange\": [134, 194],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"fast CW\",\n          \"speedEnd\": \"slow CW\"\n        },\n        {\n          \"dmxRange\": [195, 255],\n          \"type\": \"Rotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Automatic Zoom\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 9],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [10, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Zoom\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\"\n        }\n      ]\n    },\n    \"Pan/Tilt Automatics\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 7],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [8, 32],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 1\"\n        },\n        {\n          \"dmxRange\": [33, 58],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 2\"\n        },\n        {\n          \"dmxRange\": [59, 84],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto Program 3\"\n        },\n        {\n          \"dmxRange\": [85, 110],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 4\"\n        },\n        {\n          \"dmxRange\": [111, 136],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 5\"\n        },\n        {\n          \"dmxRange\": [137, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 6\"\n        },\n        {\n          \"dmxRange\": [163, 188],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 7\"\n        },\n        {\n          \"dmxRange\": [189, 214],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 8\"\n        },\n        {\n          \"dmxRange\": [215, 240],\n          \"type\": \"Effect\",\n          \"effectName\": \"Automatic Program 9\"\n        },\n        {\n          \"dmxRange\": [241, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound Control Pan Tilt\",\n          \"soundControlled\": true\n        }\n      ]\n    },\n    \"Pan/Tilt Speed\": {\n      \"capability\": {\n        \"type\": \"PanTiltSpeed\",\n        \"speedStart\": \"fast\",\n        \"speedEnd\": \"slow\"\n      }\n    },\n    \"Reset\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 189],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [190, 210],\n          \"type\": \"Maintenance\",\n          \"hold\": \"10s\",\n          \"comment\": \"Reset\"\n        },\n        {\n          \"dmxRange\": [211, 255],\n          \"type\": \"NoFunction\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"name\": \"Color Macros\",\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 10],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"dmxRange\": [11, 15],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Deep Hell Red\",\n          \"colors\": [\"#ff0f00\"]\n        },\n        {\n          \"dmxRange\": [16, 20],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Wacko Red\",\n          \"colors\": [\"#ff2300\"]\n        },\n        {\n          \"dmxRange\": [21, 25],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Liberal Democrat Orange\",\n          \"colors\": [\"#ff6400\"]\n        },\n        {\n          \"dmxRange\": [26, 30],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Jovial Merryment Orange\",\n          \"colors\": [\"#ff7d00\"]\n        },\n        {\n          \"dmxRange\": [31, 35],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Chrome Gold Yellow\",\n          \"colors\": [\"#ffaa00\"]\n        },\n        {\n          \"dmxRange\": [36, 40],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Supernova Cheese\",\n          \"colors\": [\"#ffd000\"]\n        },\n        {\n          \"dmxRange\": [41, 45],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"dmxRange\": [46, 50],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Liquid Neon\",\n          \"colors\": [\"#c8ff00\"]\n        },\n        {\n          \"dmxRange\": [51, 55],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Poisonous Puddle Green\",\n          \"colors\": [\"#a0ff00\"]\n        },\n        {\n          \"dmxRange\": [56, 60],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Gleaming Lime Green\",\n          \"colors\": [\"#6eff00\"]\n        },\n        {\n          \"dmxRange\": [61, 65],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm Laser Green\",\n          \"colors\": [\"#46ff00\"]\n        },\n        {\n          \"dmxRange\": [66, 70],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"dmxRange\": [71, 75],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"EW Salbador Green\",\n          \"colors\": [\"#00ff0a\"]\n        },\n        {\n          \"dmxRange\": [76, 80],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"The Brightest Forest Green\",\n          \"colors\": [\"#00ff19\"]\n        },\n        {\n          \"dmxRange\": [81, 85],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Electric Bush Cool Green\",\n          \"colors\": [\"#00ff2d\"]\n        },\n        {\n          \"dmxRange\": [86, 90],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Lime Green Car\",\n          \"colors\": [\"#00ff46\"]\n        },\n        {\n          \"dmxRange\": [91, 95],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blinded By The Mint Green\",\n          \"colors\": [\"#00ff78\"]\n        },\n        {\n          \"dmxRange\": [96, 100],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Cyan\",\n          \"colors\": [\"#00ffff\"]\n        },\n        {\n          \"dmxRange\": [101, 105],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sky Blue\",\n          \"colors\": [\"#00b4ff\"]\n        },\n        {\n          \"dmxRange\": [106, 110],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ocean Blue\",\n          \"colors\": [\"#0046ff\"]\n        },\n        {\n          \"dmxRange\": [111, 115],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"dmxRange\": [116, 120],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Minecraft Water Ocean Blue\",\n          \"colors\": [\"#1400ff\"]\n        },\n        {\n          \"dmxRange\": [121, 125],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ultramarine\",\n          \"colors\": [\"#3200ff\"]\n        },\n        {\n          \"dmxRange\": [126, 130],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Ianthine Indigo\",\n          \"colors\": [\"#5f00ff\"]\n        },\n        {\n          \"dmxRange\": [131, 135],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Volcanic Lightning Purple\",\n          \"colors\": [\"#8200ff\"]\n        },\n        {\n          \"dmxRange\": [136, 140],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Mr O Purple\",\n          \"colors\": [\"#be00ff\"]\n        },\n        {\n          \"dmxRange\": [141, 145],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Phlox\",\n          \"colors\": [\"#e100ff\"]\n        },\n        {\n          \"dmxRange\": [146, 150],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"dmxRange\": [151, 155],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Nicki Minaj Bright Magenta\",\n          \"colors\": [\"#ff00dc\"]\n        },\n        {\n          \"dmxRange\": [156, 160],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Hollywood Cerise\",\n          \"colors\": [\"#ff00aa\"]\n        },\n        {\n          \"dmxRange\": [161, 165],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Folly\",\n          \"colors\": [\"#ff005f\"]\n        },\n        {\n          \"dmxRange\": [166, 170],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Sweet Cherry Chapstick Red\",\n          \"colors\": [\"#ff0044\"]\n        },\n        {\n          \"dmxRange\": [171, 175],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Midnight Blue\",\n          \"colors\": [\"#000028\"]\n        },\n        {\n          \"dmxRange\": [176, 180],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"British Phone Box Red\",\n          \"colors\": [\"#ff0015\"]\n        },\n        {\n          \"dmxRange\": [181, 185],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Absolutely Bright Red\",\n          \"colors\": [\"#ff0007\"]\n        },\n        {\n          \"dmxRange\": [186, 190],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"White\",\n          \"colors\": [\"#ffffff\"]\n        },\n        {\n          \"dmxRange\": [191, 195],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Red\",\n          \"colors\": [\"#ff0000\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [196, 200],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Venomous Blood Red\",\n          \"colors\": [\"#7d0000\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [201, 205],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green\",\n          \"colors\": [\"#00ff00\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [206, 210],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Green Hills\",\n          \"colors\": [\"#007800\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [211, 215],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Blue\",\n          \"colors\": [\"#0000ff\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [216, 220],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"A Stack Of Blue\",\n          \"colors\": [\"#000064\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [221, 225],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Darker Blues Music\",\n          \"colors\": [\"#000032\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [226, 230],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Warm Yellow Sweater\",\n          \"colors\": [\"#c6910f\"]\n        },\n        {\n          \"dmxRange\": [231, 235],\n          \"type\": \"ColorPreset\",\n          \"comment\": \"Orche\",\n          \"colors\": [\"#c69111\"],\n          \"colorTemperature\": \"cold\"\n        },\n        {\n          \"dmxRange\": [236, 245],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        },\n        {\n          \"dmxRange\": [246, 255],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"13-channel\",\n      \"shortName\": \"13ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Tilt\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Red Master\",\n        \"Green Master\",\n        \"Blue Master\",\n        \"White Master\",\n        \"Zoom\",\n        \"Lens Rotation\",\n        \"Color Macros\",\n        \"Automatic Zoom\",\n        \"Pan/Tilt Automatics\"\n      ]\n    },\n    {\n      \"name\": \"25-channel\",\n      \"shortName\": \"25ch\",\n      \"channels\": [\n        \"Pan\",\n        \"Pan fine\",\n        \"Tilt\",\n        \"Tilt fine\",\n        \"Pan/Tilt Speed\",\n        \"Dimmer\",\n        \"Strobe\",\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": [\n            \"Segment 1\",\n            \"Segment 2\",\n            \"Segment 3\"\n          ],\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\",\n            \"White $pixelKey\"\n          ]\n        },\n        \"Zoom\",\n        \"Lens Rotation\",\n        \"Color Macros\",\n        \"Automatic Zoom\",\n        \"Pan/Tilt Automatics\",\n        \"Reset\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/led-hellball-3-rgb.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Hellball 3 RGB\",\n  \"shortName\": \"VarytecLedHellball3\",\n  \"categories\": [\"Flower\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Anonymous\"],\n    \"createDate\": \"2020-02-19\",\n    \"lastModifyDate\": \"2020-02-19\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/278299_c_278299_r3_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/varytec_led_hellball_3_rgb.htm\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=aZWRgRL9f_E\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [180, 160, 180],\n    \"weight\": 0.8,\n    \"power\": 15,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"3× 3W RGB LEDs\"\n    }\n  },\n  \"availableChannels\": {\n    \"Strobe\": {\n      \"constant\": true,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    },\n    \"Red\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Rotation (Pan)\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Pan\",\n          \"angleStart\": \"0deg\",\n          \"angleEnd\": \"180deg\",\n          \"helpWanted\": \"Are the angles correct?\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"PanContinuous\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        }\n      ]\n    },\n    \"Shows\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 5],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [6, 127],\n          \"type\": \"Effect\",\n          \"effectName\": \"Built-in shows\",\n          \"helpWanted\": \"At which DMX value can which show be selected?\"\n        },\n        {\n          \"dmxRange\": [128, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-controlled shows\",\n          \"soundControlled\": true,\n          \"helpWanted\": \"At which DMX value can which show be selected?\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"default\",\n      \"channels\": [\n        \"Strobe\",\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Rotation (Pan)\",\n        \"Shows\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/varytec/led-theater-spot-100.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"LED Theater Spot 100\",\n  \"shortName\": \"VarytecThSpot100\",\n  \"categories\": [\"Dimmer\"],\n  \"meta\": {\n    \"authors\": [\"benni\"],\n    \"createDate\": \"2019-03-16\",\n    \"lastModifyDate\": \"2026-01-30\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://images.static-thomann.de/pics/atg/atgdata/document/manual/414220_c_414220_427226_r5_en_online.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.thomann.de/intl/varytec_led_theater_spot_100_3000k.htm\"\n    ],\n    \"video\": [\n      \"https://www.thomann.de/gb/thomanntv_video_varytec_led_theater_spot_100_3000k_5959.html\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [160, 185, 260],\n    \"weight\": 5,\n    \"power\": 115,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"100W COB LED\",\n      \"colorTemperature\": 3000\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 45]\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 0],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [1, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"slow\",\n          \"speedEnd\": \"fast\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    },\n    {\n      \"name\": \"2-channel\",\n      \"shortName\": \"2ch\",\n      \"channels\": [\n        \"Dimmer\",\n        \"Strobe\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/velleman/aeron-250-ii.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Aeron 250 II\",\n  \"categories\": [\"Scanner\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Max Jöhnk\"],\n    \"createDate\": \"2021-09-14\",\n    \"lastModifyDate\": \"2021-09-14\"\n  },\n  \"comment\": \"VDP250SC8M2\",\n  \"links\": {\n    \"manual\": [\n      \"https://cdn.velleman.eu/downloads/4/vdp250sc8m2gbnlfresd.pdf\"\n    ],\n    \"productPage\": [\n      \"https://www.velleman.eu/products/view/?id=371050\"\n    ],\n    \"video\": [\n      \"https://www.youtube.com/watch?v=K54gwldy2_8\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [535, 295, 180],\n    \"weight\": 13.95,\n    \"power\": 350,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"lamp not included\"\n    }\n  },\n  \"wheels\": {\n    \"Color Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Magenta\",\n          \"colors\": [\"#ff00ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Yellow\",\n          \"colors\": [\"#ffff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Orange\",\n          \"colors\": [\"#ff8000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Green\",\n          \"colors\": [\"#00ff00\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Red\",\n          \"colors\": [\"#ff0000\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Blue\",\n          \"colors\": [\"#0000ff\"]\n        },\n        {\n          \"type\": \"Color\",\n          \"name\": \"Violet\",\n          \"colors\": [\"#7f00ff\"]\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"slots\": [\n        {\n          \"type\": \"Open\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        },\n        {\n          \"type\": \"Gobo\"\n        }\n      ]\n    }\n  },\n  \"availableChannels\": {\n    \"Shutter / Strobe\": {\n      \"highlightValue\": 255,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 128],\n          \"type\": \"Intensity\",\n          \"brightnessStart\": \"0%\",\n          \"brightnessEnd\": \"100%\"\n        },\n        {\n          \"dmxRange\": [129, 133],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        },\n        {\n          \"dmxRange\": [134, 243],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"fast\",\n          \"speedEnd\": \"slow\",\n          \"randomTiming\": true\n        },\n        {\n          \"dmxRange\": [244, 249],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Closed\"\n        },\n        {\n          \"dmxRange\": [250, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Open\"\n        }\n      ]\n    },\n    \"Color Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Wheel\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 1\n        },\n        {\n          \"dmxRange\": [16, 31],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 2\n        },\n        {\n          \"dmxRange\": [32, 47],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 3\n        },\n        {\n          \"dmxRange\": [48, 63],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 4\n        },\n        {\n          \"dmxRange\": [64, 79],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 5\n        },\n        {\n          \"dmxRange\": [80, 95],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 6\n        },\n        {\n          \"dmxRange\": [96, 111],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 7\n        },\n        {\n          \"dmxRange\": [112, 127],\n          \"type\": \"WheelSlot\",\n          \"slotNumber\": 8\n        },\n        {\n          \"dmxRange\": [128, 191],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [192, 255],\n          \"type\": \"WheelRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Gobo Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speed\": \"stop\"\n        },\n        {\n          \"dmxRange\": [16, 135],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [136, 255],\n          \"type\": \"WheelSlotRotation\",\n          \"wheel\": \"Gobo Wheel\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Pan\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Pan\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Tilt\": {\n      \"defaultValue\": 128,\n      \"capability\": {\n        \"type\": \"Tilt\",\n        \"angleStart\": \"0%\",\n        \"angleEnd\": \"100%\",\n        \"helpWanted\": \"Can you provide exact angles?\"\n      }\n    },\n    \"Prism Rotation\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 63],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [64, 159],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CW\",\n          \"speedEnd\": \"fast CW\"\n        },\n        {\n          \"dmxRange\": [160, 255],\n          \"type\": \"PrismRotation\",\n          \"speedStart\": \"slow CCW\",\n          \"speedEnd\": \"fast CCW\"\n        }\n      ]\n    },\n    \"Focus\": {\n      \"capability\": {\n        \"type\": \"Focus\",\n        \"distanceStart\": \"near\",\n        \"distanceEnd\": \"far\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Shutter / Strobe\",\n        \"Color Wheel\",\n        \"Gobo Wheel\",\n        \"Gobo Rotation\",\n        \"Pan\",\n        \"Tilt\",\n        \"Prism Rotation\",\n        \"Focus\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/venue/thintri64.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"ThinTri64\",\n  \"shortName\": \"VenueThinTri64\",\n  \"categories\": [\"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Felix Edelmann\"],\n    \"createDate\": \"2018-02-04\",\n    \"lastModifyDate\": \"2018-07-21\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://venuelightingeffects.com/wp-content/uploads/2016/03/Venue_by_Proline_ThinTri_38_64_Manual.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [252, 227, 84],\n    \"weight\": 1.8,\n    \"power\": 39,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 3W RGB LED\"\n    },\n    \"lens\": {\n      \"degreesMinMax\": [15, 15]\n    }\n  },\n  \"availableChannels\": {\n    \"Red\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which color macros can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"Strobe\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 127],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [128, 159],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorFade\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [160, 191],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"3 colors\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [192, 224],\n          \"type\": \"Effect\",\n          \"effectPreset\": \"ColorJump\",\n          \"comment\": \"7 colors\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [225, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound-active mode\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    },\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\",\n        \"Color Macros\",\n        \"Strobe / Speed / Sound Sensitivity\",\n        \"Mode\",\n        \"Dimmer\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red\",\n        \"Green\",\n        \"Blue\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/venue/tristrip3z.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"TriStrip3Z\",\n  \"shortName\": \"VenueTriStrip3Z\",\n  \"categories\": [\"Pixel Bar\", \"Effect\", \"Color Changer\"],\n  \"meta\": {\n    \"authors\": [\"Flo Edelmann\"],\n    \"createDate\": \"2018-01-25\",\n    \"lastModifyDate\": \"2018-08-24\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://venuelightingeffects.com/wp-content/uploads/2016/03/Venue_by_Proline_TriStrip3Z_Manual.pdf\"\n    ]\n  },\n  \"physical\": {\n    \"dimensions\": [1042, 60, 138],\n    \"weight\": 2.8,\n    \"power\": 27,\n    \"DMXconnector\": \"3-pin\",\n    \"bulb\": {\n      \"type\": \"12x 3W RGB LED\",\n      \"lumens\": 2062\n    },\n    \"lens\": {\n      \"degreesMinMax\": [27, 27]\n    }\n  },\n  \"matrix\": {\n    \"pixelKeys\": [\n      [\n        [\"Zone 3\", \"Zone 2\", \"Zone 1\"]\n      ]\n    ],\n    \"pixelGroups\": {\n      \"All Zones\": \"all\"\n    }\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"defaultValue\": 0,\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    },\n    \"Strobe\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"Strobe\",\n          \"speedStart\": \"0Hz\",\n          \"speedEnd\": \"20Hz\"\n        }\n      ]\n    },\n    \"Dimmer Speed\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 51],\n          \"type\": \"NoFunction\",\n          \"comment\": \"Preset dimmer speed from display menu\"\n        },\n        {\n          \"dmxRange\": [52, 101],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"off\"\n        },\n        {\n          \"dmxRange\": [102, 152],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"fast\"\n        },\n        {\n          \"dmxRange\": [153, 203],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"50%\"\n        },\n        {\n          \"dmxRange\": [204, 255],\n          \"type\": \"Maintenance\",\n          \"comment\": \"Dimmer speed\",\n          \"parameter\": \"slow\"\n        }\n      ]\n    },\n    \"Color Macros\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 15],\n          \"type\": \"NoFunction\"\n        },\n        {\n          \"dmxRange\": [16, 255],\n          \"type\": \"ColorPreset\",\n          \"helpWanted\": \"Which color macros can be selected at which DMX values?\"\n        }\n      ]\n    },\n    \"RGB / Auto Speed\": {\n      \"capability\": {\n        \"type\": \"EffectSpeed\",\n        \"speedStart\": \"slow\",\n        \"speedEnd\": \"fast\"\n      }\n    },\n    \"Sound Sensitivity\": {\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 10],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivity\": \"off\"\n        },\n        {\n          \"dmxRange\": [11, 255],\n          \"type\": \"SoundSensitivity\",\n          \"soundSensitivityStart\": \"low\",\n          \"soundSensitivityEnd\": \"high\"\n        }\n      ]\n    },\n    \"RGB / Auto Mode\": {\n      \"defaultValue\": 0,\n      \"capabilities\": [\n        {\n          \"dmxRange\": [0, 31],\n          \"type\": \"NoFunction\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Strobe\"\n          }\n        },\n        {\n          \"dmxRange\": [32, 63],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUp\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [64, 95],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampDown\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [96, 114],\n          \"type\": \"ShutterStrobe\",\n          \"shutterEffect\": \"RampUpDown\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [115, 122],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 1\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [123, 130],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 2\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [131, 138],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 3\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [139, 146],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 4\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [147, 154],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 5\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [155, 162],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 6\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [163, 170],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 7\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [171, 178],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 8\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [179, 186],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 9\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [187, 194],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 10\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [195, 202],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 11\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [203, 210],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 12\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [211, 218],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 13\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [219, 226],\n          \"type\": \"Effect\",\n          \"effectName\": \"Auto program 14\",\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"RGB / Auto Speed\"\n          }\n        },\n        {\n          \"dmxRange\": [227, 255],\n          \"type\": \"Effect\",\n          \"effectName\": \"Sound program\",\n          \"soundControlled\": true,\n          \"switchChannels\": {\n            \"Strobe / Speed / Sound Sensitivity\": \"Sound Sensitivity\"\n          }\n        }\n      ]\n    }\n  },\n  \"templateChannels\": {\n    \"Red $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Red\"\n      }\n    },\n    \"Green $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Green\"\n      }\n    },\n    \"Blue $pixelKey\": {\n      \"capability\": {\n        \"type\": \"ColorIntensity\",\n        \"color\": \"Blue\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"3-channel\",\n      \"shortName\": \"3ch\",\n      \"channels\": [\n        \"Red All Zones\",\n        \"Green All Zones\",\n        \"Blue All Zones\"\n      ]\n    },\n    {\n      \"name\": \"6-channel\",\n      \"shortName\": \"6ch\",\n      \"channels\": [\n        \"Red All Zones\",\n        \"Green All Zones\",\n        \"Blue All Zones\",\n        \"Dimmer\",\n        \"Strobe\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"8-channel\",\n      \"shortName\": \"8ch\",\n      \"channels\": [\n        \"Red All Zones\",\n        \"Green All Zones\",\n        \"Blue All Zones\",\n        \"Color Macros\",\n        \"Strobe / Speed / Sound Sensitivity\",\n        \"RGB / Auto Mode\",\n        \"Dimmer\",\n        \"Dimmer Speed\"\n      ]\n    },\n    {\n      \"name\": \"9-channel\",\n      \"shortName\": \"9ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"14-channel\",\n      \"shortName\": \"14ch\",\n      \"channels\": [\n        {\n          \"insert\": \"matrixChannels\",\n          \"repeatFor\": \"eachPixelABC\",\n          \"channelOrder\": \"perPixel\",\n          \"templateChannels\": [\n            \"Red $pixelKey\",\n            \"Green $pixelKey\",\n            \"Blue $pixelKey\"\n          ]\n        },\n        \"Color Macros\",\n        \"Strobe / Speed / Sound Sensitivity\",\n        \"RGB / Auto Mode\",\n        \"Dimmer\",\n        \"Dimmer Speed\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/vrsl/disco-ball.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Disco Ball\",\n  \"categories\": [\"Effect\"],\n  \"meta\": {\n    \"authors\": [\"NATION\"],\n    \"createDate\": \"2026-01-03\",\n    \"lastModifyDate\": \"2026-01-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://github.com/AcChosen/VR-Stage-Lighting/wiki/Appendix:-Fixture-Definitions\"\n    ]\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "fixtures/vrsl/flasher.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n  \"name\": \"Flasher\",\n  \"categories\": [\"Blinder\"],\n  \"meta\": {\n    \"authors\": [\"NATION\"],\n    \"createDate\": \"2026-01-03\",\n    \"lastModifyDate\": \"2026-01-03\"\n  },\n  \"links\": {\n    \"manual\": [\n      \"https://github.com/AcChosen/VR-Stage-Lighting/wiki/Appendix:-Fixture-Definitions\"\n    ]\n  },\n  \"availableChannels\": {\n    \"Dimmer\": {\n      \"capability\": {\n        \"type\": \"Intensity\"\n      }\n    }\n  },\n  \"modes\": [\n    {\n      \"name\": \"1-channel\",\n      \"shortName\": \"1ch\",\n      \"channels\": [\n        \"Dimmer\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"target\": \"ES2021\",\n    \"strict\": true\n  },\n  \"vueCompilerOptions\": {\n    \"target\": 2.7\n  },\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}\n"
  },
  {
    "path": "lib/ajv-validator.js",
    "content": "import Ajv from 'ajv';\nimport addFormats from 'ajv-formats';\nimport importJson from './import-json.js';\n/** @import { ValidateFunction } from 'ajv' */\n\nconst ajv = new Ajv({\n  verbose: true,\n  strict: false,\n  allErrors: true,\n  discriminator: true,\n});\naddFormats(ajv);\najv.addKeyword('version');\najv.addFormat('color-hex', true);\n\n// eslint-disable-next-line unicorn/prefer-top-level-await -- https://github.com/unjs/jiti/issues/72\nconst loadSchemasPromise = (async () => {\n  const schemas = await Promise.all([\n    importJson('../schemas/capability.json', import.meta.url),\n    importJson('../schemas/channel.json', import.meta.url),\n    importJson('../schemas/definitions.json', import.meta.url),\n    importJson('../schemas/fixture-redirect.json', import.meta.url),\n    importJson('../schemas/fixture.json', import.meta.url),\n    importJson('../schemas/gobo.json', import.meta.url),\n    importJson('../schemas/manufacturers.json', import.meta.url),\n    importJson('../schemas/matrix.json', import.meta.url),\n    importJson('../schemas/plugin.json', import.meta.url),\n    importJson('../schemas/wheel-slot.json', import.meta.url),\n  ]);\n  ajv.addSchema(schemas);\n})();\n\n/**\n * @param {string} schemaName The name of the schema to load.\n * @returns {Promise<ValidateFunction>} The validate function for the specified schema.\n */\nexport default async function getAjvValidator(schemaName) {\n  await loadSchemasPromise;\n\n  const schemaId = `https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/${schemaName}.json`;\n  const validationFunction = ajv.getSchema(schemaId);\n\n  if (!validationFunction) {\n    throw new Error(`Schema '${schemaName}' not found.`);\n  }\n\n  return validationFunction;\n}\n"
  },
  {
    "path": "lib/cache-result.js",
    "content": "/**\n * Caches the passed value in the passed class instance, so that it doesn't have\n * to be recomputed. Note that the `propertyName` must be the same as the getter,\n * so that the getter is overwritten.\n * @example\n * ```js\n * class Example {\n *   get myProperty() {\n *     const result = someExpensiveComputation();\n *     return cacheResult(this, `myProperty`, result);\n *   }\n * }\n * ```\n * @see https://humanwhocodes.com/blog/2021/04/lazy-loading-property-pattern-javascript/\n * @param {object} classInstance The instance where the value should be cached.\n * @param {string} propertyName The name of the property to find this value.\n * @param {unknown} value The value to be cached.\n * @returns {unknown} The cached value, for easier chaining.\n */\nexport default function cacheResult(classInstance, propertyName, value) {\n  Object.defineProperty(classInstance, propertyName, {\n    value,\n    writable: false,\n    configurable: false,\n    enumerable: false,\n  });\n\n  return value;\n}\n"
  },
  {
    "path": "lib/create-github-issue.js",
    "content": "import './load-env-file.js';\n\nimport { Octokit } from '@octokit/rest';\n\n/**\n * @param {string} title The issue heading.\n * @param {string} body Further text describing the issue (may include markdown and newlines).\n * @param {string[] | null} [labels=[]] Array of label names the created issue should be tagged with.\n * @returns {Promise<string, Error>} A promise that resolves to the issue URL, or rejects with an error.\n */\nexport default async function createIssue(title, body, labels = []) {\n  const repository = process.env.NODE_ENV === 'production' ? 'open-fixture-library' : 'ofl-test';\n\n  const userToken = process.env.GITHUB_USER_TOKEN;\n  if (userToken === undefined) {\n    console.error('.env file does not contain GITHUB_USER_TOKEN variable');\n    throw new Error('GitHub user token was not set');\n  }\n\n  const githubClient = new Octokit({\n    auth: `token ${userToken}`,\n  });\n\n  const result = await githubClient.rest.issues.create({\n    owner: 'OpenLightingProject',\n    repo: repository,\n    title,\n    body,\n    labels,\n  });\n\n  return result.data.html_url;\n}\n"
  },
  {
    "path": "lib/create-github-pr.js",
    "content": "import './load-env-file.js';\n\nimport { Octokit } from '@octokit/rest';\nimport fixtureJsonStringify from './fixture-json-stringify.js';\nimport { getObjectSortedByKeys } from './register.js';\n/** @import { FixtureCreateResult } from './types.js' */\n\nconst repository = process.env.NODE_ENV === 'production' ? 'open-fixture-library' : 'ofl-test';\n\n/** @type {string} */\nlet branchName;\n\n/** @type {string[]} */\nlet changedFiles;\n\n/** @type {string[]} */\nlet githubErrors;\n\n/** @type {Octokit} */\nlet githubClient;\n\n/**\n * @param {FixtureCreateResult} fixtureCreateResult The object like returned by an import plugin.\n * @param {string | null} [githubUsername=null] GitHub user name of the fixture submitter.\n * @param {string | null} [githubComment=null] Additional comment for the pull request.\n * @returns {Promise<string, Error>} A promise that resolves to the pull request URL, or rejects with an error.\n */\nexport default async function createPullRequest(fixtureCreateResult, githubUsername = null, githubComment = null) {\n  const {\n    manufacturers,\n    fixtures,\n    warnings,\n    errors,\n  } = fixtureCreateResult;\n\n  const userToken = process.env.GITHUB_USER_TOKEN;\n  if (userToken === undefined) {\n    console.error('.env file does not contain GITHUB_USER_TOKEN variable');\n    throw new Error('GitHub user token was not set');\n  }\n\n  const timestamp = new Date().toISOString().replaceAll(':', '-').replace(/\\..+/, '');\n  branchName = `branch${timestamp}`;\n\n  changedFiles = [];\n  githubErrors = [];\n\n  githubClient = new Octokit({\n    auth: `token ${userToken}`,\n  });\n\n  try {\n    console.log('get latest commit hash ...');\n    const latestCommitRef = await githubClient.rest.git.getRef({\n      owner: 'OpenLightingProject',\n      repo: repository,\n      ref: 'heads/master',\n    });\n    const latestCommitHash = latestCommitRef.data.object.sha;\n    console.log(latestCommitHash);\n\n    console.log(`create new branch '${branchName}' ...`);\n    await githubClient.rest.git.createRef({\n      owner: 'OpenLightingProject',\n      repo: repository,\n      ref: `refs/heads/${branchName}`,\n      sha: latestCommitHash,\n    });\n    console.log('done');\n\n    const user = await getGithubUserInfo(githubUsername);\n\n    const skipCi = Object.keys(fixtures).length > 0;\n    await addOrUpdateFile('fixtures/manufacturers.json', 'manufacturers.json', (oldFileContent) => {\n      const mergedManufacturers = Object.assign(\n        oldFileContent\n          ? JSON.parse(oldFileContent)\n          : {\n              $schema: 'https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/manufacturers.json',\n            },\n        manufacturers,\n      );\n\n      return prettyJsonStringify(getObjectSortedByKeys(mergedManufacturers));\n    }, user, skipCi);\n\n    const fixtureEntries = Object.entries(fixtures);\n    let index = 0;\n    for (const [fixtureKey, fixture] of fixtureEntries) {\n      await addOrUpdateFile(\n        `fixtures/${fixtureKey}.json`,\n        `fixture \\`${fixtureKey}\\``,\n        (oldFileContent) => fixtureJsonStringify(fixture),\n        user,\n        index !== fixtureEntries.length - 1, // all but the last fixture should skip CI\n      );\n      index++;\n    }\n\n    console.log('create pull request ...');\n\n    const addedFixtures = changedFiles.filter((line) => line.startsWith('Add fixture'));\n    let title = `Add ${addedFixtures.length} new fixtures`;\n    if (addedFixtures.length === 1) {\n      title = addedFixtures[0];\n    }\n\n    const fixtureWarningsErrorsMarkdown = getFixtureWarningsErrorsMarkdownList(fixtures, errors, warnings);\n    const submitterNameMarkdown = getSubmitterNameMarkdown(user, githubUsername, fixtures);\n\n    const result = await githubClient.rest.pulls.create({\n      owner: 'OpenLightingProject',\n      repo: repository,\n      title,\n      body: getPrDescriptionMarkdown(submitterNameMarkdown, fixtureWarningsErrorsMarkdown, githubComment),\n      head: branchName,\n      base: 'master',\n      draft: true,\n    });\n    console.log('done');\n\n    console.log('add labels to pull request ...');\n    await githubClient.rest.issues.addLabels({\n      owner: 'OpenLightingProject',\n      repo: repository,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      issue_number: result.data.number,\n      labels: ['new-fixture', 'via-editor'],\n    });\n    console.log('done');\n\n    const pullRequestUrl = result.data.html_url;\n    console.log(`View the pull request at ${pullRequestUrl}`);\n\n    return pullRequestUrl;\n  }\n  catch (error) {\n    console.error(`Error: ${error.message}`);\n    throw error;\n  }\n}\n\n/**\n * @param {string | null} username The passed GitHub username.\n * @returns {object | null} GitHub user information about the submitter, or null if it is not a valid GitHub user.\n */\nasync function getGithubUserInfo(username) {\n  if (!username) {\n    return null;\n  }\n\n  console.log(`get info for GitHub user @${username} ...`);\n\n  try {\n    const { data: user } = await githubClient.rest.users.getByUsername({ username });\n    console.log(`done (name: ${user.name}, email: ${user.email})`);\n    return user;\n  }\n  catch {\n    console.log('error getting user');\n    return null;\n  }\n}\n\n/**\n * @param {string} submitterNameMarkdown The Markdown to display the submitter's name.\n * @param {string} fixtureWarningsErrorsMarkdown A Markdown list of all fixture warnings and errors. May be empty\n * @param {string} githubComment Additional comment for the pull request.\n * @returns {string} The pull request description body markdown.\n */\nfunction getPrDescriptionMarkdown(submitterNameMarkdown, fixtureWarningsErrorsMarkdown, githubComment) {\n  let body = changedFiles.map((line) => `* ${line}`).join('\\n');\n\n  if (githubErrors.length > 0) {\n    const githubErrorList = githubErrors.map((error) => `* ⚠️ ${error}`).join('\\n');\n    body += `\\n\\n### Errors:\\n${githubErrorList}`;\n  }\n\n  if (fixtureWarningsErrorsMarkdown.length > 0) {\n    body += '\\n\\n### Fixture warnings / errors\\n\\n';\n    body += fixtureWarningsErrorsMarkdown;\n  }\n\n  if (githubComment) {\n    body += '\\n\\n### User comment\\n\\n';\n    body += githubComment;\n  }\n\n  body += `\\n\\nThank you ${submitterNameMarkdown}!`;\n\n  return body;\n}\n\n/**\n * @param {Record<string, unknown>} fixtures The fixtures to add to the pull request.\n * @param {Record<string, unknown>} errors The errors to add to the pull request.\n * @param {Record<string, unknown>} warnings The warnings to add to the pull request.\n * @returns {string} A Markdown list of all fixture warnings and errors.\n */\nfunction getFixtureWarningsErrorsMarkdownList(fixtures, errors, warnings) {\n  let markdownList = '';\n\n  for (const fixtureKey of Object.keys(fixtures)) {\n    const fixtureErrors = errors[fixtureKey] || [];\n    const fixtureWarnings = warnings[fixtureKey] || [];\n\n    const messages = [\n      ...fixtureErrors.map((error) => `  - ❌ ${error}`),\n      ...fixtureWarnings.map((warning) => `  - ⚠️ ${warning}`),\n    ].join('\\n');\n\n    if (messages.length > 0) {\n      markdownList += `* ${fixtureKey}\\n${messages}\\n`;\n    }\n  }\n\n  return markdownList;\n}\n\n/**\n * @param {object | null} user GitHub user information about the submitter, or null if they are not a GitHub user.\n * @param {string} githubUsername The passed GitHub username.\n * @param {Record<string, unknown>} fixtures The fixtures to add to the pull request.\n * @returns {string} The submitter of the fixture(s), or the first author of the first fixture.\n */\nfunction getSubmitterNameMarkdown(user, githubUsername, fixtures) {\n  if (user) {\n    return `@${user.login}`;\n  }\n\n  if (githubUsername) {\n    return `**${githubUsername}**`;\n  }\n\n  return Object.values(fixtures)\n    .flatMap((fixture) => fixture.meta.authors)\n    .filter((author, index, list) => list.indexOf(author) === index) // filter out duplicates\n    .map((author) => `**${author}**`)\n    .join(' and ');\n}\n\n/**\n * @callback newContentFunction\n * @param {string | null} oldFileContent The text content of the old file, or null if it has not existed yet.\n * @returns {string} The new file text content.\n */\n\n/**\n * @param {string} filename The path of the file (relative to the repository root) to add or update.\n * @param {string} displayName A shorter file name to display in commit messages and PR body.\n * @param {newContentFunction} newContentFunction The callback to get the new file content from.\n * @param {object | null} user GitHub user information about the submitter, or null if they are not a GitHub user.\n * @param {boolean} [excludeFromCi=false] True if this commit should be excluded from the CI (continuous integration tests).\n * @returns {Promise} Promise that is resolved when the file is successfully / erroneously updated / added.\n */\nasync function addOrUpdateFile(filename, displayName, newContentFunction, user, excludeFromCi = false) {\n  const appendToCommitMessage = excludeFromCi ? '\\n\\n[skip ci]' : '';\n\n  let action;\n  let sha;\n  let newFileContent;\n\n  console.log(`does ${displayName} exist?`);\n\n  try {\n    const result = await githubClient.rest.repos.getContent({\n      owner: 'OpenLightingProject',\n      repo: repository,\n      path: filename,\n    });\n\n    console.log('yes -> update it ...');\n\n    const oldFileContent = Buffer.from(result.data.content, result.data.encoding).toString('utf-8');\n    newFileContent = newContentFunction(oldFileContent);\n\n    if (oldFileContent === newFileContent) {\n      console.log('no need to update, files are the same');\n      return;\n    }\n\n    action = 'Update';\n    sha = result.data.sha;\n  }\n  catch {\n    console.log('no -> create it ...');\n    action = 'Add';\n    newFileContent = newContentFunction(null);\n  }\n\n  const committer = user && user.email\n    ? {\n        name: user.name,\n        email: user.email,\n      }\n    : undefined;\n\n  try {\n    await githubClient.rest.repos.createOrUpdateFileContents({\n      owner: 'OpenLightingProject',\n      repo: repository,\n      path: filename,\n      message: `${action} ${displayName} via editor${appendToCommitMessage}`,\n      content: encodeBase64(newFileContent),\n      sha,\n      branch: branchName,\n      committer,\n    });\n\n    console.log('done');\n    changedFiles.push(`${action} ${displayName}`);\n  }\n  catch (error) {\n    console.error(`Error (${action.toLowerCase()} ${displayName}): ${error.message}`);\n    githubErrors.push(`Error (${action.toLowerCase()} ${displayName}): \\`${error.message}\\``);\n  }\n}\n\n/**\n * @param {string} string The string to encode in base 64.\n * @returns {string} The encoded string.\n */\nfunction encodeBase64(string) {\n  return Buffer.from(string).toString('base64');\n}\n\n/**\n * JSON.stringify with an extra newline character at the end.\n * @param {object} object JSON object.\n * @returns {string} String representing the given object.\n */\nfunction prettyJsonStringify(object) {\n  const string = JSON.stringify(object, null, 2);\n\n  return `${string}\\n`;\n}\n"
  },
  {
    "path": "lib/diff-plugin-outputs.js",
    "content": "import childProcess from 'child_process';\nimport { cp, mkdir, readFile, rm, writeFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { promisify, styleText } from 'util';\nimport directoryCompare from 'dir-compare';\nimport disparity from 'disparity';\nimport JSZip from 'jszip';\n\n/**\n * @typedef {object} PluginDiffOutput\n * @property {string[]} removedFiles Removed outputted files' paths.\n * @property {string[]} addedFiles Added outputted files' paths.\n * @property {object} changedFiles Changed outputted files' paths pointing to their diff.\n */\n\n/**\n * Exports the given fixtures with the current version of the given currentPlugin and diffs the results\n * against the files exported with the comparePlugin at the state of the given Git reference.\n * @param {string} currentPluginKey The key of a currently present plugin.\n * @param {string} comparePluginKey The key of a plugin that needs to be present in the given Git reference.\n * @param {string} ref The Git reference to compare with, for example `master`, `HEAD~1` or a commit reference.\n * @param {string[]} fixtures Paths to the compared fixtures, relative to the current working directory.\n * @returns {Promise<PluginDiffOutput>} Information what output files were removed, added or changed plus the diffs for changed files.\n */\nexport default async function diffPluginOutputs(currentPluginKey, comparePluginKey, ref, fixtures) {\n  const date = new Date();\n\n  // get manufacturer and fixture data later used by export plugins\n  fixtures = fixtures.map((relativePath) => {\n    const absolutePath = path.join(process.cwd(), relativePath);\n    return [\n      path.basename(path.dirname(absolutePath)), // man key\n      path.basename(absolutePath, path.extname(absolutePath)), // fix key\n    ];\n  });\n\n  console.log('## Diffing plugin output');\n  console.log('# current plugin:', currentPluginKey);\n  console.log('# compare plugin:', comparePluginKey);\n  console.log('# ref:', ref);\n  console.log('# fixtures:', fixtures.map(([manufacturer, fixture]) => `${manufacturer}/${fixture}`).join(', '));\n  console.log();\n\n  const temporaryDirectoryUrl = new URL('../tmp/', import.meta.url);\n  if (process.cwd().startsWith(fileURLToPath(temporaryDirectoryUrl))) {\n    console.error(styleText('red', '[Error]'), 'This script can\\'t be run from inside the tmp directory.');\n    process.exit(1);\n  }\n\n  const currentOutUrl = new URL('current_output/', temporaryDirectoryUrl);\n  const compareOutUrl = new URL('compare_output/', temporaryDirectoryUrl);\n\n  // delete old temp folder (if it exists) and recreate it\n  await rm(temporaryDirectoryUrl, {\n    recursive: true,\n    force: true,\n  });\n  await mkdir(temporaryDirectoryUrl, { recursive: true });\n\n  // export with current plugin script\n  try {\n    await exportFixtures(currentOutUrl, currentPluginKey, new URL('../', import.meta.url));\n  }\n  catch (error) {\n    console.error(styleText('red', '[Error]'), 'Exporting with current plugin script failed:', error);\n    process.exit(1);\n  }\n\n  // get compare script and fixture files as archive\n  const compareArchiveUrl = new URL('compare.zip', temporaryDirectoryUrl);\n  const unzipDirectoryUrl = new URL('compareFiles/', temporaryDirectoryUrl);\n\n  try {\n    await promisify(childProcess.exec)(`git archive ${ref} -o ${fileURLToPath(compareArchiveUrl)}`, {\n      cwd: fileURLToPath(new URL('../', import.meta.url)),\n      encoding: 'utf-8',\n    });\n  }\n  catch (error) {\n    console.error(styleText('red', '[Error]'), 'Failed to download compare plugin script:', error.message);\n    process.exit(1);\n  }\n\n  // unzip compare archive\n  await mkdir(unzipDirectoryUrl, { recursive: true });\n  const compareArchiveData = await readFile(compareArchiveUrl);\n  const zip = await JSZip.loadAsync(compareArchiveData);\n\n  await Promise.all(Object.values(zip.files).map(async (file) => {\n    if (file.dir) {\n      return;\n    }\n\n    const filePath = fileURLToPath(new URL(file.name, unzipDirectoryUrl));\n    await mkdir(path.dirname(filePath), { recursive: true });\n    const fileBuffer = await file.async('nodebuffer');\n    await writeFile(filePath, fileBuffer);\n  }));\n\n  // copy color-name-list to compare folder, see https://github.com/OpenLightingProject/open-fixture-library/issues/4415\n  const colorNameListUrl = new URL('node_modules/color-name-list', unzipDirectoryUrl);\n  await mkdir(fileURLToPath(colorNameListUrl), { recursive: true });\n  await cp(\n    fileURLToPath(new URL('../node_modules/color-name-list', import.meta.url)),\n    fileURLToPath(colorNameListUrl),\n    { recursive: true },\n  );\n\n  // delete compare archive\n  await rm(compareArchiveUrl, {\n    recursive: true,\n    force: true,\n  });\n\n  // export with compare plugin script\n  try {\n    await exportFixtures(compareOutUrl, comparePluginKey, unzipDirectoryUrl);\n  }\n  catch (error) {\n    console.error(styleText('red', '[Error]'), 'Exporting with compare plugin script failed:', error);\n    process.exit(1);\n  }\n\n  // find the differences\n  const outputData = await findDifferences(fileURLToPath(currentOutUrl), fileURLToPath(compareOutUrl));\n\n  console.log('Done.');\n  return outputData;\n\n  /**\n   *\n   * @param {URL} outputUrl The path where to output the exported fixtures.\n   * @param {string} pluginKey The plugin key.\n   * @param {URL} baseDirectory The OFL root directory.\n   * @returns {Promise<void>} A Promise that resolves when all exported fixtures are saved to the filesystem.\n   */\n  async function exportFixtures(outputUrl, pluginKey, baseDirectory) {\n    const plugin = await import(new URL(`plugins/${pluginKey}/export.js`, baseDirectory));\n    const { fixtureFromRepository } = await import(new URL('lib/model.js', baseDirectory));\n\n    // support export plugins before https://github.com/OpenLightingProject/open-fixture-library/pull/1623/commits/391e6045c6f0fcc0009bec924801b91790d3472c\n    const exportFunction = plugin.exportFixtures || plugin.export;\n\n    const outFiles = await exportFunction(\n      await Promise.all(fixtures.map(\n        ([manufacturer, fixture]) => fixtureFromRepository(manufacturer, fixture),\n      )),\n      {\n        baseDirectory,\n        date,\n        displayedPluginVersion: 'dummy version by diff-plugin-outputs',\n      },\n    );\n\n    return Promise.all(outFiles.map(async (outFile) => {\n      const outFilePath = fileURLToPath(new URL(outFile.name, outputUrl));\n      await mkdir(path.dirname(outFilePath), { recursive: true });\n      await writeFile(outFilePath, outFile.content);\n    }));\n  }\n}\n\n/**\n * @param {string} currentOut The output directory of the current version.\n * @param {string} compareOut The output directory of the compare version.\n * @returns {Promise<PluginDiffOutput>} The plugin diff output object.\n */\nasync function findDifferences(currentOut, compareOut) {\n  const diffResult = await directoryCompare.compare(compareOut, currentOut, {\n    compareContent: true,\n  });\n\n  /** @type {PluginDiffOutput} */\n  const outputData = {\n    removedFiles: [],\n    addedFiles: [],\n    changedFiles: {},\n  };\n\n  for (const difference of diffResult.diffSet) {\n    let name;\n\n    switch (difference.state) {\n      case 'equal': {\n        continue;\n      }\n      case 'left': {\n        name = getRelativePath(difference.relativePath, difference.name1, difference.type1);\n\n        console.log(styleText('red', `File or directory ${name} was removed.`));\n\n        outputData.removedFiles.push(name);\n        continue;\n      }\n      case 'right': {\n        name = getRelativePath(difference.relativePath, difference.name2, difference.type2);\n\n        console.log(styleText('green', `File or directory ${name} was added.`));\n\n        outputData.addedFiles.push(name);\n        continue;\n      }\n      case 'distinct': {\n        name = getRelativePath(difference.relativePath, difference.name2, difference.type2);\n        const file1 = await readFile(path.join(difference.path1, difference.name1), 'utf-8');\n        const file2 = await readFile(path.join(difference.path2, difference.name2), 'utf-8');\n\n        console.log(styleText('yellow', `Diff for ${name}`));\n        console.log(disparity.unified(file1, file2));\n\n        outputData.changedFiles[name] = disparity.unifiedNoColor(file1, file2);\n        continue;\n      }\n    }\n  }\n\n  return outputData;\n}\n\n/**\n * @param {string} relativePath The relative path to the directory containing the item. relativePath in diffSet.\n * @param {string} name The item's name. name1/name2 in diffSet.\n * @param {'file' | 'directory'} type Specifies if the item is a file or a directory. type1/type2 in diffSet.\n * @returns {string} The relative path to the item itself. Ends with an '/' if the item is a directory.\n */\nfunction getRelativePath(relativePath, name, type) {\n  if (type === 'directory') {\n    return path.join('.', relativePath, name, '/'); // the '.' removes a '/' in the beginning of the relative path\n  }\n  return path.join('.', relativePath, name);\n}\n"
  },
  {
    "path": "lib/esm-shim.cjs",
    "content": "/**\n * @fileoverview\n * There are some JSON files that need to be imported synchronously, but we\n * don't want to use the `--experimental-json-modules` command-line flag for\n * every `node` command. Thus, we require them all here in this CommonJS module\n * and re-export them for use in ECMAScript modules.\n * @see https://nodejs.org/docs/latest-v14.x/api/esm.html#esm_experimental_json_modules\n */\n\nmodule.exports.manufacturersSchema = require('../schemas/manufacturers.json');\nmodule.exports.fixtureRedirectSchema = require('../schemas/fixture-redirect.json');\nmodule.exports.fixtureSchema = require('../schemas/fixture.json');\nmodule.exports.channelSchema = require('../schemas/channel.json');\nmodule.exports.capabilitySchema = require('../schemas/capability.json');\nmodule.exports.wheelSlotSchema = require('../schemas/wheel-slot.json');\nmodule.exports.definitionsSchema = require('../schemas/definitions.json');\n"
  },
  {
    "path": "lib/fixture-features/16bit-dmx-value-resolution.js",
    "content": "import CoarseChannel from '../model/CoarseChannel.js';\n/** @import Fixture from '../model/Fixture.js' */\n\nexport default [\n  {\n    id: '16bit-capability-range',\n    name: '16bit capability range',\n    description: 'Whether a capability has a 16bit DMX value range',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.coarseChannels.some(\n      (channel) => channel.dmxValueResolution === CoarseChannel.RESOLUTION_16BIT && channel.capabilities.some(\n        (capability) => capability.rawDmxRange.start % 256 !== 0,\n      ),\n    ),\n  },\n\n  {\n    id: '16bit-default-value',\n    name: '16bit default value',\n    description: 'Whether a channel has a 16bit default value',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.coarseChannels.some(\n      (channel) => Number.isInteger(channel.jsonObject.defaultValue) && channel.defaultValue % 256 !== 0,\n    ),\n  },\n];\n"
  },
  {
    "path": "lib/fixture-features/capability-types.js",
    "content": "import { capabilityTypes } from '../../lib/schema-properties.js';\n/** @import Fixture from '../model/Fixture.js' */\n\nexport default Object.keys(capabilityTypes).map((type) => ({\n  id: `capability-type-${type}`,\n  name: `Capability type ${type}`,\n  description: `Whether the fixture has at least one capability of type '${type}'`,\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture has at least one capability of the current type\n   */\n  hasFeature: (fixture) => fixture.coarseChannels.some(\n    (channel) => channel.capabilities.some(\n      (capability) => capability.type === type,\n    ),\n  ),\n}));\n"
  },
  {
    "path": "lib/fixture-features/duplicate-channel-names.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: 'Duplicate channel names',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => {\n    const uniqueNames = new Set(fixture.allChannels.map((channel) => channel.name));\n    return uniqueNames.size < fixture.allChannels.length;\n  },\n}];\n"
  },
  {
    "path": "lib/fixture-features/fine-channels.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [\n  {\n    id: 'fine-channel-alias',\n    name: 'Fine channels (16bit)',\n    description: 'Whether a channel defines exactly one fine channel alias',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.coarseChannels.some((channel) => channel.fineChannelAliases.length === 1),\n  },\n\n  {\n    id: 'fine-channel-aliases',\n    name: 'Fine channels (>16bit)',\n    description: 'Whether a channel defines two or more fine channel aliases',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.coarseChannels.some((channel) => channel.fineChannelAliases.length > 1),\n  },\n\n  {\n    id: 'fine-channel-capabilities',\n    name: 'Fine channel capabilities',\n    description: 'Whether a channel with fine channel aliases has capabilities',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.coarseChannels.some(\n      (channel) => channel.fineChannelAliases.length > 0 && channel.capabilities.length > 1,\n    ),\n  },\n];\n"
  },
  {
    "path": "lib/fixture-features/fine-positions.js",
    "content": "import FineChannel from '../model/FineChannel.js';\n/** @import Fixture from '../model/Fixture.js' */\n\nexport default [\n  {\n    name: 'Fine before coarse',\n    description: 'Fine channel used in a mode before its coarse channel',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.modes.some((mode) =>\n      mode.channelKeys.some((channelKey, channelPos) => {\n        const channel = fixture.getChannelByKey(channelKey);\n        return channel instanceof FineChannel && channelPos < mode.getChannelIndex(channel.coarseChannel.key);\n      }),\n    ),\n  },\n\n  {\n    name: 'Fine not-adjacent after coarse',\n    description: 'Coarse channel with fine channels are not directly after each other',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.modes.some((mode) =>\n      mode.channelKeys.some((channelKey, channelPos) => {\n        const channel = fixture.getChannelByKey(channelKey);\n        return channel instanceof FineChannel && channelPos > mode.getChannelIndex(channel.coarserChannel.key) + 1;\n      }),\n    ),\n  },\n];\n"
  },
  {
    "path": "lib/fixture-features/floating-point-physicals.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n/** @import Physical from '../model/Physical.js' */\n\nconst fixtureFeatures = [\n  {\n    id: 'floating-point-dimensions',\n    name: 'Floating point dimensions',\n    description: 'In fixture physical or in a mode\\'s physical override. See [#133](https://github.com/OpenLightingProject/open-fixture-library/issues/133).',\n    properties: ['width', 'height', 'depth'],\n  },\n  {\n    id: 'floating-point-weight',\n    name: 'Floating point weight',\n    properties: ['weight'],\n  },\n  {\n    id: 'floating-point-power',\n    name: 'Floating point power',\n    properties: ['power'],\n  },\n  {\n    id: 'floating-point-color-temperature',\n    name: 'Floating point color temperature',\n    properties: ['bulbColorTemperature'],\n  },\n  {\n    id: 'floating-point-lumens',\n    name: 'Floating point lumens',\n    properties: ['bulbLumens'],\n  },\n  {\n    id: 'floating-point-lens-degrees',\n    name: 'Floating point lens degrees',\n    properties: ['lensDegreesMin', 'lensDegreesMax'],\n  },\n];\n\nexport default fixtureFeatures.map((fixtureFeature) => ({\n  ...fixtureFeature,\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => isFloatInPhysical(fixture.physical, fixtureFeature.properties) || fixture.modes.some((mode) => isFloatInPhysical(mode.physical, fixtureFeature.properties)),\n}));\n\n/**\n * @param {Physical | null} physical The physical data to check\n * @param {string[]} properties Physical properties to check\n * @returns {boolean} Whether one of the given properties have a floating point value\n */\nfunction isFloatInPhysical(physical, properties) {\n  return physical !== null && properties.some((property) => physical[property] !== null && Math.abs(physical[property]) % 1 > 0);\n}\n"
  },
  {
    "path": "lib/fixture-features/many-modes.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: 'Many modes',\n  description: 'True if the fixture has more than 15 modes.',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} True if the fixture has more than 15 modes.\n   */\n  hasFeature: (fixture) => fixture.modes.length > 15,\n}];\n"
  },
  {
    "path": "lib/fixture-features/matrices.js",
    "content": "import FineChannel from '../model/FineChannel.js';\nimport SwitchingChannel from '../model/SwitchingChannel.js';\n/** @import Fixture from '../model/Fixture.js' */\n\nexport default [\n  {\n    id: 'matrix-pixelKeys',\n    name: 'Uses pixelKeys',\n    description: 'The fixture has a matrix and has set the pixelKeys individually.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.matrix !== null && 'pixelKeys' in fixture.matrix.jsonObject,\n  },\n\n  {\n    id: 'matrix-pixelCount',\n    name: 'Uses pixelCount',\n    description: 'The fixture has a matrix and has set the pixelCount property.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.matrix !== null && 'pixelCount' in fixture.matrix.jsonObject,\n  },\n\n  {\n    id: 'matrix-pixelGroups',\n    name: 'Uses pixelGroups',\n    description: 'The fixture has a matrix and has set pixelGroups.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.matrix !== null && fixture.matrix.pixelGroupKeys.length > 0,\n  },\n\n  {\n    id: 'matrix-pixelGroups-number-constraints',\n    name: 'Uses pixelGroup number constraints',\n    description: 'The fixture has a matrix and has set pixelGroups using number constraint syntax.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.matrix !== null && Object.values(fixture.matrix.jsonObject.pixelGroups || {}).some(\n      (group) => group !== 'all' && !Array.isArray(group) && Object.keys(group).some((constraint) => ['x', 'y', 'z'].includes(constraint)),\n    ),\n  },\n\n  {\n    id: 'matrix-pixelGroups-string-constraints',\n    name: 'Uses pixelGroup string constraints',\n    description: 'The fixture has a matrix and has set pixelGroups using string constraint syntax.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.matrix !== null && Object.values(fixture.matrix.jsonObject.pixelGroups || {}).some(\n      (group) => group !== 'all' && !Array.isArray(group) && Object.keys(group).includes('name'),\n    ),\n  },\n\n  {\n    id: 'matrix-custom-layout',\n    name: 'Custom matrix layout',\n    description: 'The fixture has a matrix and it uses null pixelKeys – it is no line, rectangle or cube.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.matrix !== null && fixture.matrix.pixelKeyStructure.some(\n      (zLevel) => zLevel.some(\n        (row) => row.includes(null),\n      ),\n    ),\n  },\n\n  {\n    id: 'fine-matrix-channel',\n    name: 'Fine matrix channel',\n    description: 'The fixture repeats fine channels for matrix pixels.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.matrixChannels.some((channel) => channel instanceof FineChannel),\n  },\n\n  {\n    id: 'switching-matrix-channel',\n    name: 'Switching matrix channel',\n    description: 'The fixture repeats switching channels for matrix pixels.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.matrixChannels.some((channel) => channel instanceof SwitchingChannel),\n  },\n\n  {\n    id: 'matrix-channel-overridden',\n    name: 'Matrix channel overridden',\n    description: 'An available channel overrides a specific matrix channel (at a specific pixel).',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.availableChannels.some((channel) => fixture.matrixChannelKeys.includes(channel.key)),\n  },\n\n  {\n    id: 'matrix-channel-used-directly',\n    name: 'Matrix channel used directly',\n    description: 'If a mode contains a resolved matrix channel key in its raw channel list or if a non-matrix switching channel switches to a matrix channel.',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => {\n      const channelKeyInRawChannelList = fixture.modes.some(\n        (mode) => mode.jsonObject.channels.some(\n          (channelKey) => fixture.matrixChannelKeys.includes(channelKey),\n        ),\n      );\n\n      const channelKeyInSwitchingChannel = fixture.switchingChannels.some(\n        (swChannel) => swChannel.pixelKey === null && swChannel.switchToChannels.some(\n          (channel) => channel.pixelKey !== null,\n        ),\n      );\n\n      return channelKeyInRawChannelList || channelKeyInSwitchingChannel;\n    },\n  },\n];\n"
  },
  {
    "path": "lib/fixture-features/multiple-categories.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: 'Multiple categories',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => fixture.categories.length > 1,\n}];\n"
  },
  {
    "path": "lib/fixture-features/multiple-focuses.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: 'Multiple Focuses',\n  description: 'True if multiple Pan / Tilt channels are used in some mode.',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => fixture.modes.some((mode) => {\n    const multiPan = mode.channels.filter(\n      (channel) => channel.type === 'Pan',\n    ).length > 1;\n\n    const multiTilt = mode.channels.filter(\n      (channel) => channel.type === 'Tilt',\n    ).length > 1;\n\n    return multiPan || multiTilt;\n  }),\n}];\n"
  },
  {
    "path": "lib/fixture-features/no-physical-data.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: 'No physical',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => fixture.physical === null,\n}];\n"
  },
  {
    "path": "lib/fixture-features/null-channels.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: '`null` channels',\n  description: 'Channel list of a mode contains null, so it has an unused channel',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => fixture.nullChannels.length > 0,\n}];\n"
  },
  {
    "path": "lib/fixture-features/physical-override.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: 'Physical override',\n  description: 'Whether at least one mode uses the \\'physical\\' property',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => fixture.modes.some((mode) => mode.physicalOverride !== null),\n}];\n"
  },
  {
    "path": "lib/fixture-features/rdm.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: 'RDM',\n  description: 'Whether an RDM model ID is set',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => fixture.rdm !== null,\n}];\n"
  },
  {
    "path": "lib/fixture-features/redirect-reasons.js",
    "content": "import { fixtureRedirectProperties } from '../../lib/schema-properties.js';\nimport importJson from '../import-json.js';\n/** @import Fixture from '../model/Fixture.js' */\n\nconst registerPromise = importJson('../../fixtures/register.json', import.meta.url);\n\n/** @type {string[]} */\nconst redirectReasons = fixtureRedirectProperties.reason.enum;\n\nexport default redirectReasons.map((reason) => ({\n  id: `redirect-reason-${reason}`,\n  name: `Fixture redirect reason ${reason}`,\n  description: `Whether the fixture is a fixture redirect with reason '${reason}'`,\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {Promise<boolean>} A Promise that resolves to true if the fixture is a fixture redirect with the current reason\n   */\n  hasFeature: async (fixture) => {\n    const register = await registerPromise;\n    const manufacturerFixture = `${fixture.manufacturer.key}/${fixture.key}`;\n    const registerItem = register.filesystem[manufacturerFixture];\n    return 'redirectTo' in registerItem && registerItem.reason === reason;\n  },\n}));\n"
  },
  {
    "path": "lib/fixture-features/reused-channels.js",
    "content": "/** @import Fixture from '../model/Fixture.js' */\n\nexport default [{\n  name: 'Reused channels',\n  description: 'Whether there is at least one channel that is used in different modes',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture uses the feature\n   */\n  hasFeature: (fixture) => {\n    const usedChannels = [];\n    for (const mode of fixture.modes) {\n      for (const channel of mode.channelKeys) {\n        if (usedChannels.includes(channel)) {\n          return true;\n        }\n        usedChannels.push(channel);\n      }\n    }\n    return false;\n  },\n}];\n"
  },
  {
    "path": "lib/fixture-features/switching-channels.js",
    "content": "import FineChannel from '../model/FineChannel.js';\n/** @import Fixture from '../model/Fixture.js' */\n\nexport default [\n  {\n    id: 'switching-channels',\n    name: 'Switching channels',\n    description: 'Whether at least one channel defines switching channel aliases',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.switchingChannels.length > 0,\n  },\n  {\n    id: 'switches-fine-channels',\n    name: 'Switches fine channels',\n    description: 'Whether at least one switching channel switches fine channels',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.switchingChannels.some(\n      (switchingChannel) => switchingChannel.switchToChannels.some(\n        (channel) => channel instanceof FineChannel,\n      ),\n    ),\n  },\n  {\n    id: 'switching-channel-positions',\n    name: 'Switching channel at different positions',\n    description: 'Whether there is a switching channel that is used at different positions in different modes',\n\n    /**\n     * @param {Fixture} fixture The Fixture instance\n     * @returns {boolean} true if the fixture uses the feature\n     */\n    hasFeature: (fixture) => fixture.switchingChannels.some((switchingChannel) => {\n      const usedIndices = [];\n\n      return fixture.modes.some((mode) => {\n        const index = mode.getChannelIndex(switchingChannel.key, 'all');\n\n        // channel is not used in mode\n        if (index === -1) {\n          return false;\n        }\n\n        // channel is used at a new position\n        if (!usedIndices.includes(index) && usedIndices.length > 0) {\n          return true;\n        }\n\n        usedIndices.push(index);\n        return false;\n      });\n    }),\n  },\n];\n"
  },
  {
    "path": "lib/fixture-features/wheels.js",
    "content": "import { wheelSlotTypes } from '../../lib/schema-properties.js';\n/** @import Fixture from '../model/Fixture.js' */\n\nconst wheelTypes = [\n  ...Object.keys(wheelSlotTypes).filter((type) => !type.startsWith('AnimationGobo')),\n  'AnimationGobo',\n];\n\nconst wheelTypeFeatures = wheelTypes.map((type) => ({\n  id: `wheel-type-${type}`,\n  name: `Wheel type ${type}`,\n  description: `Whether the fixture has at least one wheel of type '${type}'`,\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture has at least one wheel of the current type\n   */\n  hasFeature: (fixture) => fixture.wheels.some(\n    (wheel) => wheel.type === type,\n  ),\n}));\n\nconst wheelSlotTypeFeatures = Object.keys(wheelSlotTypes).map((type) => ({\n  id: `wheel-slot-type-${type}`,\n  name: `Wheel slot type ${type}`,\n  description: `Whether the fixture has at least one wheel slot of type '${type}'`,\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture has at least one wheel slot of the current type\n   */\n  hasFeature: (fixture) => fixture.wheels.some(\n    (wheel) => wheel.slots.some(\n      (slot) => slot.type === type,\n    ),\n  ),\n}));\n\nconst resourceFeature = {\n  id: 'wheel-slot-uses-resource',\n  name: 'Wheel slot uses resource',\n  description: 'Whether the fixture has at least one wheel slot that references a resource',\n\n  /**\n   * @param {Fixture} fixture The Fixture instance\n   * @returns {boolean} true if the fixture has at least one wheel slot that references a resource\n   */\n  hasFeature: (fixture) => fixture.wheels.some(\n    (wheel) => wheel.slots.some(\n      (slot) => slot.resource !== null,\n    ),\n  ),\n};\n\nexport default [...wheelTypeFeatures, ...wheelSlotTypeFeatures, resourceFeature];\n"
  },
  {
    "path": "lib/fixture-json-stringify.js",
    "content": "/**\n * Basically JSON.stringify, but some fixture-related array properties are squashed\n * into one line instead of each array element having its own.\n * @param {object} object JSON object.\n * @returns {string} String representing the given object.\n */\nexport default function fixtureJsonStringify(object) {\n  let string = JSON.stringify(object, null, 2);\n\n  // make number arrays fit in one line\n  string = string.replaceAll(\n    /^( +)\"(dmxRange|range|dimensions|spacing|degreesMinMax)\": (\\[\\n[^]*?^\\1])/gm,\n    (match, spaces, key, values) => {\n      const numbers = JSON.parse(values).join(', ');\n      return `${spaces}\"${key}\": [${numbers}]`;\n    },\n  );\n\n  // make string arrays fit in one line\n  string = string.replaceAll(\n    /^( +)\"(categories|authors|fineChannelAliases|colors(?:Start|End)?)\": (\\[\\n[^]*?^\\1])/gm,\n    (match, spaces, key, values) => {\n      const strings = JSON.parse(values).map((value) => `\"${value}\"`).join(', ');\n      return `${spaces}\"${key}\": [${strings}]`;\n    },\n  );\n\n  return `${string}\\n`;\n}\n"
  },
  {
    "path": "lib/get-ajv-error-messages.js",
    "content": "// see https://github.com/epoberezkin/ajv#validation-errors\n\nconst getDetailsPerAjvKeyword = {\n  propertyNames(error, allErrors) {\n    let errorMessage = `property name '${error.params.propertyName}' is invalid`;\n\n    const relatedError = allErrors.find(\n      (otherError) => otherError.propertyName === error.params.propertyName,\n    );\n    if (relatedError) {\n      errorMessage += ` (${relatedError.message})`;\n    }\n\n    return errorMessage;\n  },\n  additionalProperties(error) {\n    return `${error.message} (${error.params.additionalProperty})`;\n  },\n  enum(error) {\n    const allowedValues = error.params.allowedValues.join(', ');\n    return `must be equal to one of [${allowedValues}]`;\n  },\n  oneOf(error) {\n    if (error.params.passingSchemas) {\n      const passingSchemas = error.params.passingSchemas.map((index) => error.schema[index]);\n      const allAreOnlyRequired = passingSchemas.every(\n        (schema) => Object.keys(schema).length === 1 && 'required' in schema,\n      );\n\n      if (allAreOnlyRequired) {\n        const properties = passingSchemas.map((schema) => schema.required.join('+')).join(' / ');\n        return `must not have a combination of the properties ${properties}`;\n      }\n    }\n\n    return error.message;\n  },\n  const(error) {\n    return `${error.message} \"${getShortenedString(error.params.allowedValue)}\"`;\n  },\n};\n\n/**\n * @param {object[]} ajvErrors The array of AJV error objects.\n * @param {string} [rootName=`root`] The display name of the root object in the error data path.\n * @returns {string} A human-readable validation error message.\n */\nexport default function getAjvErrorMessages(ajvErrors, rootName = 'root') {\n  const errors = ajvErrors.filter((error) => {\n    if ('propertyName' in error) {\n      // the information from this error will be displayed in the related `propertyNames` error\n      return false;\n    }\n\n    const isUselessError = error.keyword === 'if' && error.schema === true;\n    return !isUselessError;\n  });\n\n  return errors.map((error) => {\n    const getDetails = getDetailsPerAjvKeyword[error.keyword] || (() => error.message);\n    const details = getDetails(error, ajvErrors);\n    const errorMessage = `${rootName}${error.instancePath}${getDataDescription(error.data)} ${details}`;\n    return errorMessage.replaceAll('\\n', String.raw`\\n`);\n  });\n}\n\n/**\n * @param {unknown} data Any kind of data; not all types can be represented.\n * @returns {string} A short representation of the given data with a leading space. Empty if this is not possible.\n */\nfunction getDataDescription(data) {\n  if (typeof data === 'string') {\n    return ` \"${getShortenedString(data)}\"`;\n  }\n  if (typeof data === 'number' || typeof data === 'boolean' || data === null) {\n    return ` ${data}`;\n  }\n  if (typeof data === 'object' && 'type' in data) {\n    return ` (type: ${data.type})`;\n  }\n  return '';\n}\n\n/**\n * @param {string} string The string to shorten\n * @returns {string} The shortened string, or the original string if it's already short.\n */\nfunction getShortenedString(string) {\n  const maxLength = 30;\n  return (string.length > maxLength) ? `${string.slice(0, maxLength - 1)}…` : string;\n}\n"
  },
  {
    "path": "lib/import-json.js",
    "content": "import { readFile } from 'fs/promises';\nimport path from 'path';\n\n/**\n * @param {string | URL} jsonPath The JSON file path.\n * @param {string | URL | undefined} basePath A path from which the JSON path is resolved relative to.\n * @returns {Promise<unknown>} A Promise that resolves to the parsed JSON file content.\n */\nexport default async function importJson(jsonPath, basePath) {\n  if (typeof basePath === 'string' && !basePath.startsWith('file:')) {\n    jsonPath = path.resolve(basePath, jsonPath);\n  }\n  else if (basePath) {\n    jsonPath = new URL(jsonPath, basePath);\n  }\n\n  // see https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1273\n  const buffer = await readFile(jsonPath);\n  return JSON.parse(buffer);\n}\n"
  },
  {
    "path": "lib/load-env-file.js",
    "content": "import { fileURLToPath } from 'url';\nimport env from 'node-env-file';\n\nconst envFilePath = fileURLToPath(new URL('../.env', import.meta.url));\nenv(envFilePath, { raise: false });\n"
  },
  {
    "path": "lib/model/AbstractChannel.js",
    "content": "/** @import Fixture from './Fixture.js' */\n\n/**\n * Base class for channels.\n * @abstract\n */\nclass AbstractChannel {\n  /**\n   * Create a new AbstractChannel instance. Call this from child classes as `super(key)`.\n   * @param {string} key The channel's identifier, must be unique in the fixture.\n   * @throws {TypeError} If the AbstractChannel is instantiated directly.\n   */\n  constructor(key) {\n    if (this.constructor === AbstractChannel) {\n      throw new TypeError('Cannot instantiate AbstractChannel directly');\n    }\n\n    this._key = key;\n    this._pixelKey = null;\n  }\n\n  /**\n   * @abstract\n   * @returns {Fixture} The fixture instance this channel is associated to.\n   * @throws {TypeError} If this property is not overridden in child classes.\n   */\n  get fixture() {\n    throw new TypeError(`Class ${this.constructor.name} must implement property fixture`);\n  }\n\n  /**\n   * @returns {string} The channel key.\n   */\n  get key() {\n    return this._key;\n  }\n\n  /**\n   * Override this method for more sensible implementation.\n   * @returns {string} The channel key (as name).\n   */\n  get name() {\n    return this._key;\n  }\n\n  /**\n   * @see {@link Fixture#uniqueChannelNames}\n   * @returns {string} Unique version of this channel's name.\n   */\n  get uniqueName() {\n    return this.fixture.uniqueChannelNames[this.key];\n  }\n\n  /**\n   * @returns {string | null} The key of the pixel (group) that this channel is associated to. Defaults to null.\n   */\n  get pixelKey() {\n    return this._pixelKey;\n  }\n\n  /**\n   * @param {string | null} pixelKey The key of the pixel (group) that this channel is associated to. Set to null to dereference a channel from a pixel (group).\n   */\n  set pixelKey(pixelKey) {\n    this._pixelKey = pixelKey;\n  }\n}\n\nexport default AbstractChannel;\n"
  },
  {
    "path": "lib/model/Capability.js",
    "content": "import cacheResult from '../cache-result.js';\nimport { scaleDmxRange } from '../scale-dmx-values.js';\nimport Entity from './Entity.js';\nimport Range from './Range.js';\n/** @import CoarseChannel from './CoarseChannel.js' */\n/** @import Wheel from './Wheel.js' */\n/** @import WheelSlot from './WheelSlot.js' */\n\n/** @ignore */\nconst START_END_ENTITIES = ['speed', 'duration', 'time', 'brightness', 'slotNumber', 'angle', 'horizontalAngle', 'verticalAngle', 'colorTemperature', 'soundSensitivity', 'shakeAngle', 'shakeSpeed', 'distance', 'openPercent', 'frostIntensity', 'insertion', 'fogOutput', 'parameter'];\n\n/** @ignore */\nconst namePerType = {\n  NoFunction: (capability) => capability.comment || 'No function',\n  ShutterStrobe: (capability) => {\n    let name = {\n      Open: 'Shutter open',\n      Closed: 'Shutter closed',\n      Strobe: 'Strobe',\n      Pulse: 'Pulse strobe',\n      RampUp: 'Ramp up strobe',\n      RampDown: 'Ramp down strobe',\n      RampUpDown: 'Ramp up and down strobe',\n      Lightning: 'Lightning strobe effect',\n      Spikes: 'Spikes strobe effect',\n      Burst: 'Burst strobe effect',\n    }[capability.shutterEffect];\n\n    if (capability.randomTiming) {\n      name = `Random ${name.toLowerCase()}`;\n    }\n\n    if (capability.isSoundControlled) {\n      name += ' sound-controlled';\n    }\n\n    if (capability.speed) {\n      name += ' ';\n      name += startEndToString(capability.speed, 'speed');\n    }\n\n    if (capability.duration) {\n      name += ' ';\n      name += startEndToString(capability.duration, 'duration');\n    }\n\n    return appendInBrackets(name, capability.comment);\n  },\n  StrobeSpeed: (capability) => getSimpleCapabilityName(capability, 'Strobe speed', 'speed'),\n  StrobeDuration: (capability) => getSimpleCapabilityName(capability, 'Strobe duration', 'duration'),\n  Intensity: (capability) => getSimpleCapabilityName(capability, 'Intensity', 'brightness'),\n  ColorIntensity: (capability) => getSimpleCapabilityName(capability, capability.color, 'brightness'),\n  ColorPreset: (capability) => {\n    const name = capability.comment || 'Color preset';\n\n    if (capability.colorTemperature) {\n      return appendInBrackets(name, colorTemperaturesToString(capability.colorTemperature));\n    }\n\n    return name;\n  },\n  ColorTemperature: (capability) => getSimpleCapabilityName(capability, 'Color temperature', 'colorTemperature'),\n  Pan: (capability) => getSimpleCapabilityName(capability, 'Pan', 'angle', 'angle', true),\n  PanContinuous: (capability) => getSimpleCapabilityName(capability, 'Pan', 'speed', 'speed', true),\n  Tilt: (capability) => getSimpleCapabilityName(capability, 'Tilt', 'angle', 'angle', true),\n  TiltContinuous: (capability) => getSimpleCapabilityName(capability, 'Tilt', 'speed', 'speed', true),\n  PanTiltSpeed: (capability) => {\n    const speedOrDuration = capability.speed === null ? 'duration' : 'speed';\n    let name = 'Pan/tilt movement ';\n\n    if (capability[speedOrDuration][0].keyword === null && capability[speedOrDuration][0].unit === '%') {\n      name += `${speedOrDuration} `;\n    }\n\n    name += startEndToString(capability[speedOrDuration]);\n\n    return appendInBrackets(name, capability.comment);\n  },\n  WheelSlot: (capability) => appendInBrackets(getSlotCapabilityName(capability), capability.comment),\n  WheelShake: (capability) => {\n    let name = capability.slotNumber ? getSlotCapabilityName(capability) : capability.wheels.map((wheel) => wheel.name).join(', ');\n\n    if (capability.isShaking === 'slot') {\n      name += ' slot';\n    }\n\n    name += ' shake';\n\n    if (capability.shakeAngle) {\n      name += ' ';\n      name += startEndToString(capability.shakeAngle, 'angle', true);\n    }\n\n    if (capability.shakeSpeed) {\n      name += ' ';\n      name += startEndToString(capability.shakeSpeed, 'speed', true);\n    }\n\n    return appendInBrackets(name, capability.comment);\n  },\n  WheelSlotRotation: (capability) => {\n    let wheelSlotName;\n    if (capability.wheelSlot) {\n      wheelSlotName = capability.wheelSlot[0].name;\n    }\n    else if (capability.wheels[0]) {\n      wheelSlotName = capability.wheels[0].type.replace(/^Gobo$/, 'Gobo stencil');\n    }\n    else {\n      wheelSlotName = 'Wheel slot';\n    }\n\n    const speedOrAngle = capability.speed === null ? 'angle' : 'speed';\n    return getSimpleCapabilityName(capability, `${wheelSlotName} rotation`, speedOrAngle, speedOrAngle, true);\n  },\n  WheelRotation: (capability) => {\n    const wheelName = capability.wheels[0] ? capability.wheels[0].name : 'Wheel';\n    const speedOrAngle = capability.speed === null ? 'angle' : 'speed';\n    return getSimpleCapabilityName(capability, `${wheelName} rotation`, speedOrAngle, speedOrAngle, true);\n  },\n  Effect: (capability) => {\n    let name = capability.effectName;\n\n    if (capability.effectPreset !== null && capability.isSoundControlled) {\n      name += ' sound-controlled';\n    }\n\n    if (capability.parameter) {\n      name += ' ';\n      name += startEndToString(capability.parameter);\n    }\n\n    if (capability.speed) {\n      name += ' ';\n      name += startEndToString(capability.speed, 'speed');\n    }\n\n    if (capability.duration) {\n      name += ' ';\n      name += startEndToString(capability.duration, 'duration');\n    }\n\n    let soundSensitivity = null;\n    if (capability.soundSensitivity) {\n      soundSensitivity = `sound sensitivity ${startEndToString(capability.soundSensitivity)}`;\n    }\n\n    return appendInBrackets(name, soundSensitivity, capability.comment);\n  },\n  EffectSpeed: (capability) => getSimpleCapabilityName(capability, 'Effect speed', 'speed'),\n  EffectDuration: (capability) => getSimpleCapabilityName(capability, 'Effect duration', 'duration'),\n  EffectParameter: (capability) => {\n    const name = capability.comment || 'Effect parameter';\n    return `${name} ${startEndToString(capability.parameter)}`;\n  },\n  SoundSensitivity: (capability) => getSimpleCapabilityName(capability, 'Sound sensitivity', 'soundSensitivity'),\n  BeamAngle: (capability) => getSimpleCapabilityName(capability, 'Beam', 'angle', 'angle', true),\n  BeamPosition: (capability) => {\n    if (capability.horizontalAngle && capability.verticalAngle) {\n      return appendInBrackets(`Beam position (${startEndToString(capability.horizontalAngle)}, ${startEndToString(capability.verticalAngle)})`, capability.comment);\n    }\n\n    const orientation = capability.horizontalAngle ? 'Horizontal' : 'Vertical';\n    const angleStartEnd = capability[`${orientation.toLowerCase()}Angle`];\n\n    const hasOrientationKeyword = angleStartEnd.some(\n      (entity) => entity.keyword !== null && entity.keyword !== 'center',\n    );\n    const prefix = hasOrientationKeyword ? 'Beam position' : `${orientation} beam position`;\n    return appendInBrackets(`${prefix} ${startEndToString(angleStartEnd)}`, capability.comment);\n  },\n  Focus: (capability) => getSimpleCapabilityName(capability, 'Focus', 'distance', 'distance'),\n  Zoom: (capability) => getSimpleCapabilityName(capability, 'Zoom', 'angle', 'beam angle'),\n  Iris: (capability) => getSimpleCapabilityName(capability, 'Iris', 'openPercent', 'open'),\n  IrisEffect: (capability) => {\n    let name = `Iris ${capability.effectName}`;\n\n    if (capability.speed) {\n      name += ' ';\n      name += startEndToString(capability.speed, 'speed');\n    }\n\n    return appendInBrackets(name, capability.comment);\n  },\n  Frost: (capability) => getSimpleCapabilityName(capability, 'Frost', 'frostIntensity'),\n  FrostEffect: (capability) => {\n    let name = `Frost ${capability.effectName}`;\n\n    if (capability.speed) {\n      name += ' ';\n      name += startEndToString(capability.speed, 'speed');\n    }\n\n    return appendInBrackets(name, capability.comment);\n  },\n  Prism: (capability) => {\n    let name = 'Prism';\n\n    if (capability.speed) {\n      name += ' ';\n      name += startEndToString(capability.speed, 'speed');\n    }\n    else if (capability.angle) {\n      name += ' ';\n      name += startEndToString(capability.angle, 'angle');\n    }\n\n    return appendInBrackets(name, capability.comment);\n  },\n  PrismRotation: (capability) => {\n    const speedOrAngle = capability.speed === null ? 'angle' : 'speed';\n    return getSimpleCapabilityName(capability, 'Prism rotation', speedOrAngle, speedOrAngle, true);\n  },\n  BladeInsertion: (capability) => getSimpleCapabilityName(capability, `Blade ${capability.blade} insertion`, 'insertion'),\n  BladeRotation: (capability) => getSimpleCapabilityName(capability, `Blade ${capability.blade} rotation`, 'angle', 'angle', true),\n  BladeSystemRotation: (capability) => getSimpleCapabilityName(capability, 'Blade system rotation', 'angle', 'angle', true),\n  Fog: (capability) => {\n    let name = capability.fogType || 'Fog';\n\n    if (capability.fogOutput) {\n      name += ` ${startEndToString(capability.fogOutput)}`;\n    }\n\n    return appendInBrackets(name, capability.comment);\n  },\n  FogOutput: (capability) => getSimpleCapabilityName(capability, 'Fog output', 'fogOutput'),\n  FogType: (capability) => appendInBrackets(`Fog type: ${capability.fogType}`, capability.comment),\n  Rotation: (capability) => {\n    const speedOrAngle = capability.speed === null ? 'angle' : 'speed';\n    return getSimpleCapabilityName(capability, 'Rotation', speedOrAngle, speedOrAngle, true);\n  },\n  Speed: (capability) => getSimpleCapabilityName(capability, 'Speed', 'speed'),\n  Time: (capability) => getSimpleCapabilityName(capability, 'Time', 'time'),\n  Maintenance: (capability) => {\n    let name = capability.comment || 'Maintenance';\n\n    if (capability.parameter) {\n      name += ` ${startEndToString(capability.parameter)}`;\n    }\n\n    let holdString = null;\n    if (capability.hold) {\n      holdString = `hold ${startEndToString([capability.hold, capability.hold])}`;\n    }\n\n    return appendInBrackets(name, holdString);\n  },\n  Generic: (capability) => capability.comment || 'Generic',\n};\n\n/**\n * @ignore\n * @param {Capability} capability The capability (with a set slot property) to generate a name for.\n * @returns {string} The name for the capability, without the comment appended (if any).\n */\nfunction getSlotCapabilityName(capability) {\n  if (capability.wheelSlot === null) {\n    // should only happen when fixture is invalid anyway\n    return 'Unknown wheel slot';\n  }\n\n  return capability.slotNumber[0].number === capability.slotNumber[1].number\n    ? capability.wheelSlot[0].name\n    : capability.wheelSlot.map((slot) => slot.name).join(' … ');\n}\n\n/**\n * A capability represents a range of a channel.\n */\nclass Capability {\n  /**\n   * @returns {string[]} Type-specific properties that may have a start and an end value.\n   */\n  static get START_END_ENTITIES() {\n    return START_END_ENTITIES;\n  }\n\n  /**\n   * Create a new Capability instance.\n   * @param {object} jsonObject The capability data from the channel's JSON.\n   * @param {Resolution} resolution How fine this capability is declared.\n   * @param {CoarseChannel} channel The channel instance this channel is associated to.\n   */\n  constructor(jsonObject, resolution, channel) {\n    this._jsonObject = jsonObject;\n    this._resolution = resolution;\n    this._channel = channel;\n    this._dmxRangePerResolution = [];\n  }\n\n  /**\n   * @returns {object} The capability data from the channel's JSON.\n   */\n  get jsonObject() {\n    return this._jsonObject;\n  }\n\n  /**\n   * @returns {Range} The capability's DMX bounds in the channel's highest resolution.\n   */\n  get dmxRange() {\n    return this.getDmxRangeWithResolution(this._channel.maxResolution);\n  }\n\n  /**\n   * @returns {Range} The capability's DMX bounds from the JSON data.\n   */\n  get rawDmxRange() {\n    return this.getDmxRangeWithResolution(this._resolution);\n  }\n\n  /**\n   * @param {number} desiredResolution The grade of resolution the dmxRange should be scaled to.\n   * @returns {Range} The capability's DMX bounds scaled (down) to the given resolution.\n   */\n  getDmxRangeWithResolution(desiredResolution) {\n    this._channel.ensureProperResolution(desiredResolution);\n\n    if (!this._dmxRangePerResolution[desiredResolution]) {\n      this._dmxRangePerResolution[desiredResolution] = new Range(scaleDmxRange(\n        this._jsonObject.dmxRange[0], this._jsonObject.dmxRange[1], this._resolution, desiredResolution,\n      ));\n    }\n\n    return this._dmxRangePerResolution[desiredResolution];\n  }\n\n  /**\n   * @returns {string} Describes which feature is controlled by this capability.\n   */\n  get type() {\n    return this._jsonObject.type;\n  }\n\n  /**\n   * @returns {string} Short one-line description of the capability, generated from the capability's type and type-specific properties.\n   */\n  get name() {\n    if (this.type in namePerType) {\n      return cacheResult(this, 'name', namePerType[this.type](this));\n    }\n\n    return cacheResult(this, 'name', `${this.type}: ${this.comment}`);\n  }\n\n  /**\n   * @returns {boolean} Whether this capability has a comment set.\n   */\n  get hasComment() {\n    return 'comment' in this._jsonObject;\n  }\n\n  /**\n   * @returns {string} Short additional information on this capability\n   */\n  get comment() {\n    return this._jsonObject.comment || '';\n  }\n\n  /**\n   * @returns {boolean} Whether this capability has the same effect from the start to the end.\n   */\n  get isStep() {\n    const steppedStartEndProperties = this.usedStartEndEntities.every(\n      (property) => this[property][0].number === this[property][1].number,\n    );\n    const steppedColors = !this.colors || this.colors.isStep;\n\n    return cacheResult(this, 'isStep', steppedStartEndProperties && steppedColors);\n  }\n\n  /**\n   * @returns {boolean} Whether this capability ranges from a high to a low value (e.g. speed fast…slow).\n   */\n  get isInverted() {\n    if (this.isStep) {\n      return cacheResult(this, 'isInverted', false);\n    }\n\n    const proportionalProperties = this.usedStartEndEntities.filter(\n      (property) => this[property][0].number !== this[property][1].number,\n    );\n\n    const isInverted = proportionalProperties.length > 0 && proportionalProperties.every(\n      (property) => Math.abs(this[property][0].number) > Math.abs(this[property][1].number),\n    );\n    return cacheResult(this, 'isInverted', isInverted);\n  }\n\n  /**\n   * @returns {string[]} Names of non-null properties with (maybe equal) start/end value.\n   */\n  get usedStartEndEntities() {\n    return cacheResult(this, 'usedStartEndEntities', Capability.START_END_ENTITIES.filter(\n      (property) => this[property] !== null,\n    ));\n  }\n\n  /**\n   * @param {Capability} nextCapability The next capability after this one.\n   * @returns {boolean} Whether this capability's end value equals the given capability's start value, i. e. one can fade from this capability to the given one.\n   */\n  canCrossfadeTo(nextCapability) {\n    if (this.type !== nextCapability.type) {\n      return false;\n    }\n\n    if (this.usedStartEndEntities.length === 0 || this.usedStartEndEntities.length !== nextCapability.usedStartEndEntities.length) {\n      return false;\n    }\n\n    const usesSameStartEndEntities = this.usedStartEndEntities.every(\n      (property) => nextCapability.usedStartEndEntities.includes(property),\n    );\n    if (!usesSameStartEndEntities) {\n      return false;\n    }\n\n    return this.usedStartEndEntities.every((property) => {\n      const tolerance = property === 'slotNumber' ? 0 : 1;\n      const delta = nextCapability[property][0].number - this[property][1].number;\n      return Math.abs(delta) <= tolerance;\n    });\n  }\n\n  /**\n   * @returns {string | null} A string describing the help that is needed for this capability, or null if no help is needed.\n   */\n  get helpWanted() {\n    return this._jsonObject.helpWanted || null;\n  }\n\n  /**\n   * @returns {'start' | 'center' | 'end' | 'hidden'} The method which DMX value to set when this capability is chosen in a lighting software's auto menu.\n   */\n  get menuClick() {\n    return this._jsonObject.menuClick || 'start';\n  }\n\n  /**\n   * @returns {number} The DMX value to set when this capability is chosen in a lighting software's auto menu.\n   */\n  get menuClickDmxValue() {\n    return this.getMenuClickDmxValueWithResolution(this._channel.maxResolution);\n  }\n\n  /**\n   * @param {number} desiredResolution The grade of resolution the dmxRange should be scaled to.\n   * @returns {number} The DMX value (scaled to the given resolution) to set when this capability is chosen in a lighting software's auto menu, or -1 if the capability should be hidden in the auto menu.\n   */\n  getMenuClickDmxValueWithResolution(desiredResolution) {\n    const dmxRange = this.getDmxRangeWithResolution(desiredResolution);\n\n    switch (this.menuClick) {\n      case 'start': {\n        return dmxRange.start;\n      }\n      case 'center': {\n        return dmxRange.center;\n      }\n      case 'end': {\n        return dmxRange.end;\n      }\n      case 'hidden': {\n        return -1;\n      }\n      default: {\n        throw new Error(`Unknown menuClick value '${this.menuClick}' in capability '${this.name}' (${this.rawDmxRange}).`);\n      }\n    }\n  }\n\n  /**\n   * @returns {Record<string, string>} Switching channel aliases mapped to the channel key to which the switching channel should be set to when this capability is activated.\n   */\n  get switchChannels() {\n    return this._jsonObject.switchChannels || {};\n  }\n\n  /**\n   * TYPE-SPECIFIC PROPERTIES (no start-end)\n   */\n\n  /**\n   * @returns {string | null} Behavior for the shutter, for example 'Closed', 'Strobe' or 'Pulse'. Defaults to null.\n   */\n  get shutterEffect() {\n    return this._jsonObject.shutterEffect || null;\n  }\n\n  /**\n   * @returns {'Red' | 'Green' | 'Blue' | 'Cyan' | 'Magenta' | 'Yellow' | 'Amber' | 'White' | 'Warm White' | 'Cold White' | 'UV' | 'Lime' | 'Indigo' | null} The color of the lamp that is controlled by this ColorIntensity capability. Defaults to null.\n   */\n  get color() {\n    return this._jsonObject.color || null;\n  }\n\n  /**\n   * @returns {object | null} The color hex codes for each visually distinguishable light beam. Defaults to null.\n   */\n  get colors() {\n    let startColors = this._jsonObject.colors;\n    let endColors = this._jsonObject.colors;\n    let isStep = true;\n\n    const isColorWheelSlot = () => this.wheelSlot !== null && this.wheelSlot[0].colors !== null && this.wheelSlot[1].colors !== null;\n\n    if (isColorWheelSlot()) {\n      startColors = this.wheelSlot[0].colors;\n      endColors = this.wheelSlot[1].colors;\n      isStep = this.slotNumber[0].number === this.slotNumber[1].number;\n    }\n    else if ('colorsStart' in this._jsonObject) {\n      startColors = this._jsonObject.colorsStart;\n      endColors = this._jsonObject.colorsEnd;\n      isStep = false;\n    }\n\n    if (!startColors) {\n      return cacheResult(this, 'colors', null);\n    }\n\n    return cacheResult(this, 'colors', {\n      startColors,\n      endColors,\n      allColors: isStep ? [...startColors] : [...startColors, ...endColors],\n      isStep,\n    });\n  }\n\n  /**\n   * @returns {Wheel[]} The wheels this capability refers to. The array has one or more elements in wheel-related capabilities, zero otherwise.\n   */\n  get wheels() {\n    let wheelNames;\n\n    if ('wheel' in this._jsonObject) {\n      wheelNames = [this._jsonObject.wheel].flat();\n    }\n    else if (this.type.includes('Wheel')) {\n      // default to channel name\n      wheelNames = [this._channel.name];\n    }\n    else {\n      wheelNames = [];\n    }\n\n    return cacheResult(this, 'wheels', wheelNames.map(\n      (wheelName) => this._channel.fixture.getWheelByName(wheelName),\n    ));\n  }\n\n  /**\n   * @param {string | RegExp} slotType The type of the slot to check. Can be a regular expression to be checked against the type.\n   * @returns {boolean} True if the capability references a slot (or range of slots) of the given type, false otherwise.\n   */\n  isSlotType(slotType) {\n    const slotTypeRegExp = slotType instanceof RegExp ? slotType : new RegExp(`^${slotType}$`);\n\n    const isCorrectSlotType = (slot) => slotTypeRegExp.test(slot.type) || (['Open', 'Closed'].includes(slot.type) && slotTypeRegExp.test(this.wheels[0].type));\n\n    return this.slotNumber !== null && this.wheelSlot.every((slot) => {\n      return isCorrectSlotType(slot)\n        || (slot.type === 'Split' && isCorrectSlotType(slot.floorSlot) && isCorrectSlotType(slot.ceilSlot));\n    });\n  }\n\n  /**\n   * Use only in `WheelShake` capabilities!\n   * @returns {'slot' | 'wheel'} The fixture component that is shaking.\n   */\n  get isShaking() {\n    return this.jsonObject.isShaking || 'wheel';\n  }\n\n  /**\n   * @returns {string | null} Describes the effect that this capability activates. May be a pretty name for an effect preset. Defaults to null.\n   */\n  get effectName() {\n    if ('effectName' in this._jsonObject) {\n      return cacheResult(this, 'effectName', this._jsonObject.effectName);\n    }\n\n    if ('effectPreset' in this._jsonObject) {\n      const effectName = {\n        ColorFade: 'Color fade',\n        ColorJump: 'Color jump',\n      }[this._jsonObject.effectPreset];\n\n      return cacheResult(this, 'effectName', effectName);\n    }\n\n    return cacheResult(this, 'effectName', null);\n  }\n\n  /**\n   * @returns {string | null} Describes the effect that this capability activates by using a predefined, standard name. Defaults to null.\n   */\n  get effectPreset() {\n    return this._jsonObject.effectPreset || null;\n  }\n\n  /**\n   * @returns {boolean} Whether this effect is controlled by sound perceived by a microphone. Defaults to false.\n   */\n  get isSoundControlled() {\n    return this._jsonObject.soundControlled === true;\n  }\n\n  /**\n   * @returns {boolean} Whether this capability's speed / duration varies by a random offset. Defaults to false.\n   */\n  get randomTiming() {\n    return this._jsonObject.randomTiming === true;\n  }\n\n  /**\n   * @returns {'Top' | 'Right' | 'Bottom' | 'Left' | number | null} At which position the blade is attached. Defaults to null.\n   */\n  get blade() {\n    return this._jsonObject.blade || null;\n  }\n\n  /**\n   * @returns {'Fog' | 'Haze' | null} The kind of fog that should be emitted. Defaults to null.\n   */\n  get fogType() {\n    return this._jsonObject.fogType || null;\n  }\n\n  /**\n   * @returns {Entity | null} How long this capability should be selected to take effect. Defaults to null.\n   */\n  get hold() {\n    if ('hold' in this._jsonObject) {\n      return cacheResult(this, 'hold', Entity.createFromEntityString(this._jsonObject.hold));\n    }\n\n    return cacheResult(this, 'hold', null);\n  }\n\n  /**\n   * TYPE-SPECIFIC PROPERTIES (only start-end)\n   */\n\n  /**\n   * @returns {Entity[] | null} Start and end speed values. Defaults to null.\n   */\n  get speed() {\n    return cacheResult(this, 'speed', this._getStartEndArray('speed'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end duration values. Defaults to null.\n   */\n  get duration() {\n    return cacheResult(this, 'duration', this._getStartEndArray('duration'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end time values. Defaults to null.\n   */\n  get time() {\n    return cacheResult(this, 'time', this._getStartEndArray('time'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end brightness values. Defaults to null.\n   */\n  get brightness() {\n    let brightness = this._getStartEndArray('brightness');\n\n    // default to off->bright for (Color)Intensity capabilities\n    if (brightness === null && ['Intensity', 'ColorIntensity'].includes(this.type)) {\n      brightness = [Entity.createFromEntityString('off'), Entity.createFromEntityString('bright')];\n    }\n\n    return cacheResult(this, 'brightness', brightness);\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end slot numbers. Defaults to null.\n   */\n  get slotNumber() {\n    return cacheResult(this, 'slotNumber', this._getStartEndArray('slotNumber'));\n  }\n\n  /**\n   * @returns {WheelSlot[] | null} Start and end wheel slot objects this capability is referencing. Defaults to null.\n   */\n  get wheelSlot() {\n    if (this.slotNumber === null) {\n      return cacheResult(this, 'wheelSlot', null);\n    }\n\n    if (this.wheels.length !== 1) {\n      throw new RangeError('When accessing the current wheel slot, the referenced wheel must be unambiguous.');\n    }\n\n    if (this.wheels[0]) {\n      return cacheResult(this, 'wheelSlot', this.slotNumber.map(\n        (slotNumber) => this.wheels[0].getSlot(slotNumber.number),\n      ));\n    }\n\n    return cacheResult(this, 'wheelSlot', null);\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end angle values. Defaults to null.\n   */\n  get angle() {\n    return cacheResult(this, 'angle', this._getStartEndArray('angle'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end horizontal angle values. Defaults to null.\n   */\n  get horizontalAngle() {\n    return cacheResult(this, 'horizontalAngle', this._getStartEndArray('horizontalAngle'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end vertical angle values. Defaults to null.\n   */\n  get verticalAngle() {\n    return cacheResult(this, 'verticalAngle', this._getStartEndArray('verticalAngle'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end colorTemperature values. Defaults to null.\n   */\n  get colorTemperature() {\n    return cacheResult(this, 'colorTemperature', this._getStartEndArray('colorTemperature'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end sound sensitivity values. Defaults to null.\n   */\n  get soundSensitivity() {\n    return cacheResult(this, 'soundSensitivity', this._getStartEndArray('soundSensitivity'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end shake angle values. Defaults to null.\n   */\n  get shakeAngle() {\n    return cacheResult(this, 'shakeAngle', this._getStartEndArray('shakeAngle'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end shake speed values. Defaults to null.\n   */\n  get shakeSpeed() {\n    return cacheResult(this, 'shakeSpeed', this._getStartEndArray('shakeSpeed'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end distance values. Defaults to null.\n   */\n  get distance() {\n    return cacheResult(this, 'distance', this._getStartEndArray('distance'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end openPercent values. Defaults to null.\n   */\n  get openPercent() {\n    return cacheResult(this, 'openPercent', this._getStartEndArray('openPercent'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end frostIntensity values. Defaults to null.\n   */\n  get frostIntensity() {\n    return cacheResult(this, 'frostIntensity', this._getStartEndArray('frostIntensity'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end insertion values. Defaults to null.\n   */\n  get insertion() {\n    return cacheResult(this, 'insertion', this._getStartEndArray('insertion'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end fogOutput values. Defaults to null.\n   */\n  get fogOutput() {\n    return cacheResult(this, 'fogOutput', this._getStartEndArray('fogOutput'));\n  }\n\n  /**\n   * @returns {Entity[] | null} Start and end parameter values. Defaults to null.\n   */\n  get parameter() {\n    return cacheResult(this, 'parameter', this._getStartEndArray('parameter'));\n  }\n\n  /**\n   * Parses a property that has start and end variants by generating an array with start and end value.\n   * @private\n   * @param {string} property The base property name. 'Start' and 'End' will be appended to get the start/end variants.\n   * @returns {Entity[] | null} Start and end value of the property (may be equal), parsed to Entity instances. null if it isn't defined in JSON.\n   */\n  _getStartEndArray(property) {\n    if (property in this._jsonObject) {\n      return [\n        this._jsonObject[property],\n        this._jsonObject[property],\n      ].map((value) => Entity.createFromEntityString(value));\n    }\n    if (`${property}Start` in this._jsonObject) {\n      return [\n        this._jsonObject[`${property}Start`],\n        this._jsonObject[`${property}End`],\n      ].map((value) => Entity.createFromEntityString(value));\n    }\n    return null;\n  }\n}\n\nexport default Capability;\n\n/**\n * @ignore\n * @param {Capability} capability The capability to generate a name for.\n * @param {string} name The capability type display name.\n * @param {string} property The property to append to the capability type name.\n * @param {string} [propertyName=null] An optional name describing the property to be added if a percentaged value is used. Doesn't need to be the model's property name.\n * @param {boolean} [propertyNameBeforeValue=false] Whether to put the property name before the percentaged value or after.\n * @returns {string} The generated capability name.\n */\nfunction getSimpleCapabilityName(capability, name, property, propertyName = null, propertyNameBeforeValue = false) {\n  const propertyString = startEndToString(capability[property], propertyName, propertyNameBeforeValue);\n  return appendInBrackets(`${name} ${propertyString}`, capability.comment);\n}\n\n/**\n * @ignore\n * @param {string} string The original string without appending or brackets.\n * @param {...(string | undefined | null)} inBrackets Strings that should be added in brackets to the given original string. Invalid strings are ignored.\n * @returns {string} The given string, appended with a space and brackets containing all valid inBracket strings.\n */\nfunction appendInBrackets(string, ...inBrackets) {\n  inBrackets = inBrackets.filter(\n    (inBracket) => inBracket !== undefined && inBracket !== null && inBracket !== '',\n  );\n\n  if (inBrackets.length === 0) {\n    return string;\n  }\n\n  const inBracketsString = inBrackets.join(', ');\n  return `${string} (${inBracketsString})`;\n}\n\n/**\n * @ignore\n * @param {Entity[]} colorTemperature Start and end entities of color temperature.\n * @returns {string} A self-explaining string describing the color temperature (and its progress, if given) by using the keywords \"warm\" and \"cold\" for percentaged values.\n */\nfunction colorTemperaturesToString([start, end]) {\n  if (start.keyword || start.unit !== '%') {\n    return startEndToString([start, end]);\n  }\n\n  if (start.equals(end)) {\n    return colorTemperatureToString(start.number);\n  }\n\n  if (start <= 0) {\n    if (end <= 0) {\n      // both warm\n      return `${-start}…${-end}% warm`;\n    }\n\n    // warm to cold\n    return `${-start}% warm … ${end}% cold`;\n  }\n\n  if (end <= 0) {\n    // cold to warm\n    return `${start}% cold … ${-end}% warm`;\n  }\n\n  // both cold\n  return `${start}…${end}% cold`;\n\n  /**\n   * @param {number} temperature A numerical value of a percentaged color temperature.\n   * @returns {string} Either \"XY% warm\", \"XY% cold\" or \"default\".\n   */\n  function colorTemperatureToString(temperature) {\n    if (temperature < 0) {\n      return `${-temperature}% warm`;\n    }\n    if (temperature > 0) {\n      return `${temperature}% cold`;\n    }\n    return 'default';\n  }\n}\n\n/**\n * @ignore\n * @param {Entity[]} startEndEntities Array of start and end entities of a property.\n * @param {string} [propertyName=null] An optional name describing the property to be added if a percentaged value is used. Doesn't need to be the model's property name.\n * @param {boolean} [propertyNameBeforeValue=false] Whether to put the property name before the percentaged value or after.\n * @returns {string} A self-explaining string describing the property value (including start-end information, if given).\n */\nfunction startEndToString([start, end], propertyName = null, propertyNameBeforeValue = false) {\n  if (start.keyword) {\n    return handleKeywords();\n  }\n\n  const unitAliases = {\n    'deg': '°',\n    'm^3/min': 'm³/min',\n  };\n\n  const unit = unitAliases[start.unit] || start.unit;\n\n  const words = [];\n\n  if (start.equals(end)) {\n    words.push(`${start.number}${unit}`);\n  }\n  else {\n    words.push(`${start.number}…${end.number}${unit}`);\n  }\n\n  if (propertyName && unit === '%') {\n    words.push(propertyName);\n  }\n\n  if (propertyNameBeforeValue) {\n    words.reverse();\n  }\n\n  return words.join(' ');\n\n  /**\n   * @returns {string} The startToEndString, if only the entities' keywords are considered.\n   */\n  function handleKeywords() {\n    if (start.equals(end)) {\n      return start.keyword;\n    }\n\n    // if both entities' keywords contain a direction specifier\n    const hasSpecifier = / (?:CW|CCW|reverse)$/;\n    if (hasSpecifier.test(start.keyword) && hasSpecifier.test(end.keyword)) {\n      const [speedStart, specifierStart] = start.keyword.split(' ');\n      const [speedEnd, specifierEnd] = end.keyword.split(' ');\n\n      if (specifierStart === specifierEnd) {\n        return `${specifierStart} ${speedStart}…${speedEnd}`;\n      }\n    }\n\n    return `${start.keyword}…${end.keyword}`;\n  }\n}\n"
  },
  {
    "path": "lib/model/CoarseChannel.js",
    "content": "import cacheResult from '../cache-result.js';\nimport { scaleDmxValue } from '../scale-dmx-values.js';\nimport AbstractChannel from './AbstractChannel.js';\nimport Capability from './Capability.js';\nimport Entity from './Entity.js';\nimport FineChannel from './FineChannel.js';\nimport SwitchingChannel from './SwitchingChannel.js';\n/** @import Fixture from './Fixture.js' */\n/** @import Mode from './Mode.js' */\n\n/** @ignore */\nconst channelTypeConstraints = {\n  'Single Color': ['ColorIntensity'],\n  'Multi-Color': {\n    required: ['ColorPreset', 'WheelSlot'],\n    predicate: (channel) => channel.capabilities.every(\n      (capability) => capability.type !== 'WheelSlot' || (capability.wheels[0] && capability.wheels[0].type === 'Color'),\n    ),\n  },\n  'Pan': ['Pan', 'PanContinuous'],\n  'Tilt': ['Tilt', 'TiltContinuous'],\n  'Focus': ['Focus'],\n  'Zoom': ['Zoom'],\n  'Iris': ['Iris', 'IrisEffect'],\n  'Gobo': {\n    required: ['WheelSlot', 'WheelShake'],\n    predicate: (channel) => channel.capabilities.every(\n      (capability) => capability.wheels.every((wheel) => wheel && wheel.type === 'Gobo'),\n    ),\n  },\n  'Prism': ['Prism'],\n  'Color Temperature': ['ColorTemperature'],\n  'Effect': ['Effect', 'EffectParameter', 'Frost', 'FrostEffect', 'SoundSensitivity', 'WheelSlot'],\n  'Strobe': {\n    required: ['ShutterStrobe'],\n    predicate: (channel) => channel.capabilities.some(\n      (capability) => capability.type === 'ShutterStrobe' && !['Open', 'Closed'].includes(capability.shutterEffect),\n    ),\n  },\n  'Shutter': ['ShutterStrobe', 'BladeInsertion', 'BladeRotation', 'BladeSystemRotation'],\n  'Fog': ['Fog', 'FogOutput', 'FogType'],\n  'Speed': ['StrobeSpeed', 'StrobeDuration', 'PanTiltSpeed', 'EffectSpeed', 'EffectDuration', 'BeamAngle', 'BeamPosition', 'PrismRotation', 'Rotation', 'Speed', 'Time', 'WheelSlotRotation', 'WheelRotation', 'WheelShake'],\n  'Maintenance': ['Maintenance'],\n  'Intensity': ['Intensity', 'Generic'],\n  'NoFunction': ['NoFunction'],\n};\n\n/**\n * A single DMX channel, either created as availableChannel or resolved templateChannel.\n * Only the MSB (most significant byte) channel if it's a multi-byte channel.\n * @extends AbstractChannel\n */\nclass CoarseChannel extends AbstractChannel {\n  /**\n   * 1 for 8bit, 2 for 16bit, ...\n   * @typedef {number} Resolution\n   */\n\n  /**\n   * @returns {Resolution} Resolution of an 8bit channel.\n   */\n  static get RESOLUTION_8BIT() {\n    return 1;\n  }\n\n  /**\n   * @returns {Resolution} Resolution of a 16bit channel.\n   */\n  static get RESOLUTION_16BIT() {\n    return 2;\n  }\n\n  /**\n   * @returns {Resolution} Resolution of a 24bit channel.\n   */\n  static get RESOLUTION_24BIT() {\n    return 3;\n  }\n\n  /**\n   * @returns {Resolution} Resolution of a 32bit channel.\n   */\n  static get RESOLUTION_32BIT() {\n    return 4;\n  }\n\n  /**\n   * Create a new CoarseChannel instance.\n   * @param {string} key The channel's identifier, must be unique in the fixture.\n   * @param {object} jsonObject The channel data from the fixture's JSON.\n   * @param {Fixture} fixture The fixture instance this channel is associated to.\n   */\n  constructor(key, jsonObject, fixture) {\n    super(key);\n    this._jsonObject = jsonObject;\n    this._fixture = fixture;\n  }\n\n  /**\n   * @returns {object} The channel data from the fixture's JSON.\n   */\n  get jsonObject() {\n    return this._jsonObject;\n  }\n\n  /**\n   * Overrides [`AbstractChannel.fixture`]{@link AbstractChannel#fixture}.\n   * @returns {Fixture} The fixture instance this channel is associated to.\n   */\n  get fixture() {\n    return this._fixture;\n  }\n\n  /**\n   * Overrides [`AbstractChannel.name`]{@link AbstractChannel#name}.\n   * @returns {string} The channel name if present or else the channel key.\n   */\n  get name() {\n    return this._jsonObject.name || this.key;\n  }\n\n  /**\n   * @returns {string} The channel type, derived from the channel's capability types.\n   */\n  get type() {\n    const type = Object.keys(channelTypeConstraints).find((potentialType) => {\n      let constraints = channelTypeConstraints[potentialType];\n\n      if (Array.isArray(constraints)) {\n        constraints = {\n          required: constraints,\n        };\n      }\n\n      const requiredCapabilityTypeUsed = this.capabilities.some(\n        (capability) => constraints.required.includes(capability.type),\n      );\n\n      const predicateFulfilled = !('predicate' in constraints) || constraints.predicate(this);\n\n      return requiredCapabilityTypeUsed && predicateFulfilled;\n    }) || 'Unknown';\n\n    return cacheResult(this, 'type', type);\n  }\n\n  /**\n   * @returns {string | null} The color of an included ColorIntensity capability, null if there's no such capability.\n   */\n  get color() {\n    const color = this.capabilities.find((capability) => capability.type === 'ColorIntensity')?.color;\n    return cacheResult(this, 'color', color ?? null);\n  }\n\n  /**\n   * @returns {string[]} This channel's fine channel aliases, ordered by resolution (coarsest first).\n   */\n  get fineChannelAliases() {\n    return this._jsonObject.fineChannelAliases || [];\n  }\n\n  /**\n   * @returns {FineChannel[]} This channel's fine channels, ordered by resolution (coarsest first).\n   */\n  get fineChannels() {\n    return cacheResult(this, 'fineChannels', this.fineChannelAliases.map(\n      (alias) => new FineChannel(alias, this),\n    ));\n  }\n\n  /**\n   * @returns {Resolution} How fine this channel can be used at its maximum. Equals the amount of coarse and fine channels.\n   */\n  get maxResolution() {\n    return 1 + this.fineChannelAliases.length;\n  }\n\n  /**\n   * Checks the given resolution if it can safely be used in this channel.\n   * @param {Resolution} uncheckedResolution The resolution to be checked.\n   * @throws {RangeError} If the given resolution is invalid in this channel.\n   */\n  ensureProperResolution(uncheckedResolution) {\n    if (uncheckedResolution > this.maxResolution || uncheckedResolution < CoarseChannel.RESOLUTION_8BIT || uncheckedResolution % 1 !== 0) {\n      throw new RangeError('resolution must be a positive integer not greater than maxResolution');\n    }\n  }\n\n  /**\n   * @returns {Resolution} How fine this channel is declared in the JSON data. Defaults to {@link CoarseChannel#maxResolution}.\n   */\n  get dmxValueResolution() {\n    if ('dmxValueResolution' in this._jsonObject) {\n      const resolutionStringToResolution = {\n        '8bit': CoarseChannel.RESOLUTION_8BIT,\n        '16bit': CoarseChannel.RESOLUTION_16BIT,\n        '24bit': CoarseChannel.RESOLUTION_24BIT,\n      };\n\n      return cacheResult(this, 'dmxValueResolution', resolutionStringToResolution[this._jsonObject.dmxValueResolution]);\n    }\n\n    return cacheResult(this, 'dmxValueResolution', this.maxResolution);\n  }\n\n  /**\n   * @param {Mode} mode The mode in which this channel is used.\n   * @param {SwitchingChannelBehavior} switchingChannelBehavior How switching channels are treated, see {@link Mode#getChannelIndex}.\n   * @returns {Resolution} How fine this channel is used in the given mode. 0 if the channel isn't used at all.\n   */\n  getResolutionInMode(mode, switchingChannelBehavior) {\n    const channelKeys = [this.key, ...this.fineChannelAliases];\n    const usedChannels = channelKeys.filter(\n      (channelKey) => mode.getChannelIndex(channelKey, switchingChannelBehavior) !== -1,\n    );\n\n    return usedChannels.length;\n  }\n\n  /**\n   * @returns {number} The maximum DMX value in the highest possible resolution. E.g. 65535 for a 16bit channel.\n   */\n  get maxDmxBound() {\n    return Math.pow(256, this.maxResolution) - 1;\n  }\n\n  /**\n   * @returns {boolean} Whether this channel has a defaultValue.\n   */\n  get hasDefaultValue() {\n    return 'defaultValue' in this._jsonObject;\n  }\n\n  /**\n   * @returns {number} The DMX value this channel initially should be set to. Specified in the finest possible resolution. Defaults to 0.\n   */\n  get defaultValue() {\n    return this.getDefaultValueWithResolution(this.maxResolution);\n  }\n\n  /**\n   * @private\n   * @returns {Record<Resolution, number>} The default DMX value of this channel in the given resolution, for all resolutions up to the channel's maximum resolution.\n   */\n  get _defaultValuePerResolution() {\n    let rawDefaultValue = this._jsonObject.defaultValue || 0;\n\n    if (!Number.isInteger(rawDefaultValue)) {\n      const percentage = Entity.createFromEntityString(rawDefaultValue).number / 100;\n      rawDefaultValue = Math.floor(percentage * (Math.pow(256, this.dmxValueResolution) - 1));\n    }\n\n    const defaultValuePerResolution = {};\n    for (let index = 1; index <= this.maxResolution; index++) {\n      defaultValuePerResolution[index] = scaleDmxValue(rawDefaultValue, this.dmxValueResolution, index);\n    }\n\n    return cacheResult(this, '_defaultValuePerResolution', defaultValuePerResolution);\n  }\n\n  /**\n   * @param {Resolution} desiredResolution The grade of resolution the defaultValue should be scaled to.\n   * @returns {number} The DMX value this channel initially should be set to, scaled to match the given resolution.\n   */\n  getDefaultValueWithResolution(desiredResolution) {\n    this.ensureProperResolution(desiredResolution);\n\n    return this._defaultValuePerResolution[desiredResolution];\n  }\n\n  /**\n   * @returns {boolean} Whether this channel has a highlightValue.\n   */\n  get hasHighlightValue() {\n    return 'highlightValue' in this._jsonObject;\n  }\n\n  /**\n   * @returns {number} A DMX value that \"highlights\" the function of this channel. Specified in the finest possible resolution. Defaults to the highest possible DMX value.\n   */\n  get highlightValue() {\n    return this.getHighlightValueWithResolution(this.maxResolution);\n  }\n\n  /**\n   * @private\n   * @returns {Record<Resolution, number>} The highlight DMX value of this channel in the given resolution, for all resolutions up to the channel's maximum resolution.\n   */\n  get _highlightValuePerResolution() {\n    let rawHighlightValue = this._jsonObject.highlightValue;\n\n    if (!Number.isInteger(rawHighlightValue)) {\n      const maxDmxBoundInResolution = Math.pow(256, this.dmxValueResolution) - 1;\n\n      if (this.hasHighlightValue) {\n        const percentage = Entity.createFromEntityString(rawHighlightValue).number / 100;\n        rawHighlightValue = Math.floor(percentage * maxDmxBoundInResolution);\n      }\n      else {\n        rawHighlightValue = maxDmxBoundInResolution;\n      }\n    }\n\n    const highlightValuePerResolution = {};\n    for (let index = 1; index <= this.maxResolution; index++) {\n      highlightValuePerResolution[index] = scaleDmxValue(rawHighlightValue, this.dmxValueResolution, index);\n    }\n\n    return cacheResult(this, '_highlightValuePerResolution', highlightValuePerResolution);\n  }\n\n  /**\n   * @param {Resolution} desiredResolution The grade of resolution the highlightValue should be scaled to.\n   * @returns {number} A DMX value that \"highlights\" the function of this channel, scaled to match the given resolution.\n   */\n  getHighlightValueWithResolution(desiredResolution) {\n    this.ensureProperResolution(desiredResolution);\n\n    return this._highlightValuePerResolution[desiredResolution];\n  }\n\n  /**\n   * @returns {boolean} Whether a fader for this channel should be displayed upside down.\n   */\n  get isInverted() {\n    const proportionalCapabilities = this.capabilities.filter((capability) => !capability.isStep);\n    const isInverted = proportionalCapabilities.length > 0 && proportionalCapabilities.every((capability) => capability.isInverted);\n    return cacheResult(this, 'isInverted', isInverted);\n  }\n\n  /**\n   * @returns {boolean} Whether this channel should constantly stay at the same value.\n   */\n  get isConstant() {\n    return 'constant' in this._jsonObject && this._jsonObject.constant;\n  }\n\n  /**\n   * @returns {boolean} Whether switching from one DMX value to another in this channel can be faded smoothly.\n   */\n  get canCrossfade() {\n    if (this.capabilities.length === 1) {\n      return cacheResult(this, 'canCrossfade', !this.isConstant && this.type !== 'NoFunction');\n    }\n\n    const canCrossfade = this.capabilities.every(\n      (capability, index, array) => index + 1 === array.length || capability.canCrossfadeTo(array[index + 1]),\n    ) && this.capabilities.some((capability) => !capability.isStep);\n\n    return cacheResult(this, 'canCrossfade', canCrossfade);\n  }\n\n  /**\n   * @returns {'HTP' | 'LTP'} The channel's behavior when being affected by multiple faders: HTP (Highest Takes Precedent) or LTP (Latest Takes Precedent).\n   */\n  get precedence() {\n    return 'precedence' in this._jsonObject ? this._jsonObject.precedence : 'LTP';\n  }\n\n  /**\n   * @returns {string[]} Aliases of the switching channels defined by this channel, ordered by appearance in the JSON.\n   */\n  get switchingChannelAliases() {\n    return cacheResult(this, 'switchingChannelAliases', Object.keys(this.capabilities[0].switchChannels));\n  }\n\n  /**\n   * @returns {SwitchingChannel[]} Switching channels defined by this channel, ordered by appearance in the JSON.\n   */\n  get switchingChannels() {\n    return cacheResult(this, 'switchingChannels', this.switchingChannelAliases.map(\n      (alias) => new SwitchingChannel(alias, this),\n    ));\n  }\n\n  /**\n   * @returns {string[]} The keys of the channels to which the switching channels defined by this channel can be switched to.\n   */\n  get switchToChannelKeys() {\n    return cacheResult(this, 'switchToChannelKeys', this.switchingChannels.flatMap(\n      (switchingChannel) => switchingChannel.switchToChannelKeys,\n    ));\n  }\n\n  /**\n   * @returns {Capability[]} All capabilities of this channel, ordered by DMX range.\n   */\n  get capabilities() {\n    if ('capability' in this._jsonObject) {\n      const capabilityData = {\n        dmxRange: [0, Math.pow(256, this.dmxValueResolution) - 1],\n        ...this._jsonObject.capability,\n      };\n\n      return cacheResult(this, 'capabilities', [\n        new Capability(capabilityData, this.dmxValueResolution, this),\n      ]);\n    }\n\n    return cacheResult(this, 'capabilities', this._jsonObject.capabilities.map(\n      (capability) => new Capability(capability, this.dmxValueResolution, this),\n    ));\n  }\n\n  /**\n   * @returns {boolean} True if help is needed in a capability of this channel, false otherwise.\n   */\n  get isHelpWanted() {\n    return cacheResult(this, 'isHelpWanted', this.capabilities.some(\n      (capability) => capability.helpWanted !== null,\n    ));\n  }\n}\n\nexport default CoarseChannel;\n"
  },
  {
    "path": "lib/model/Entity.js",
    "content": "import cacheResult from '../cache-result.js';\n\nconst KEYWORDS = {\n  'fast reverse': -100,\n  'slow reverse': -1,\n  'stop': 0,\n  'slow': 1,\n  'fast': 100,\n  'fast CCW': -100,\n  'slow CCW': -1,\n  'slow CW': 1,\n  'fast CW': 100,\n  'instant': 0,\n  'short': 1,\n  'long': 100,\n  'near': 1,\n  'far': 100,\n  'off': 0,\n  'dark': 1,\n  'bright': 100,\n  'warm': -100,\n  'CTO': -100,\n  'default': 0,\n  'cold': 100,\n  'CTB': 100,\n  'weak': 1,\n  'strong': 100,\n  'left': -100,\n  'top': -100,\n  'center': 0,\n  'right': 100,\n  'bottom': 100,\n  'closed': 0,\n  'narrow': 1,\n  'wide': 100,\n  'low': 1,\n  'high': 100,\n  'out': 0,\n  'in': 100,\n  'open': 100,\n  'small': 1,\n  'big': 100,\n};\n\nconst unitConversions = {\n  ms: {\n    baseUnit: 's',\n    factor: 1 / 1000,\n  },\n  bpm: {\n    baseUnit: 'Hz',\n    factor: 1 / 60,\n  },\n  rpm: {\n    baseUnit: 'Hz',\n    factor: 1 / 60,\n  },\n};\n\n/**\n * A physical entity with numerical value and unit information.\n */\nclass Entity {\n  /**\n   * Creates a new Entity instance.\n   * @param {number} number The numerical value.\n   * @param {string} unit The unit symbol, e.g. 'Hz'. Must be the same as in the schema.\n   * @param {string | null} keyword The keyword if defined using a keyword. Optional.\n   */\n  constructor(number, unit, keyword = null) {\n    this._number = number;\n    this._unit = unit;\n    this._keyword = keyword;\n  }\n\n  /**\n   * @returns {number} The numerical value of this entity.\n   */\n  get number() {\n    return this._number;\n  }\n\n  /**\n   * @returns {string} The unit symbol, like \"Hz\" or \"%\".\n   */\n  get unit() {\n    return this._unit;\n  }\n\n  /**\n   * @returns {string | null} The used keyword, or null if no keyword was used.\n   */\n  get keyword() {\n    return this._keyword || null;\n  }\n\n  /**\n   * @returns {Entity} An entity of the same value, but scaled to the base unit. Returns the entity itself if it is already in the base unit.\n   */\n  get baseUnitEntity() {\n    if (Object.keys(unitConversions).includes(this.unit)) {\n      const { baseUnit, factor } = unitConversions[this.unit];\n      return cacheResult(this, 'baseUnitEntity', new Entity(this.number * factor, baseUnit, this.keyword));\n    }\n\n    return cacheResult(this, 'baseUnitEntity', this);\n  }\n\n  /**\n   * Used to allow comparing like `entity1 < entity2`\n   * @returns {number} The numerical value of this entity.\n   */\n  valueOf() {\n    return this.number;\n  }\n\n  /**\n   * @returns {string} The entity string that could be used in the fixture's JSON data.\n   */\n  toString() {\n    return this.keyword || `${this.number}${this.unit}`;\n  }\n\n  /**\n   * @param {Entity} anotherEntity Another Entity instance to compare with.\n   * @returns {boolean} Whether this entity exactly equals the given one.\n   */\n  equals(anotherEntity) {\n    return (\n      this.number === anotherEntity.number\n      && this.unit === anotherEntity.unit\n      && this.keyword === anotherEntity.keyword\n    );\n  }\n\n  /**\n   * @param {string} entityString The string for a single entity value from the JSON data. May also be a keyword.\n   * @returns {Entity} A new entity from the given string.\n   * @throws {Error} If the entity string is invalid.\n   */\n  static createFromEntityString(entityString) {\n    if (entityString in KEYWORDS) {\n      return new Entity(KEYWORDS[entityString], '%', entityString);\n    }\n\n    try {\n      const [, numberString, unitString] = /^([\\d.-]+)(.*)$/.exec(entityString);\n      return new Entity(Number.parseFloat(numberString), unitString);\n    }\n    catch {\n      throw new Error(`'${entityString}' is not a valid entity string.`);\n    }\n  }\n}\n\nexport default Entity;\n"
  },
  {
    "path": "lib/model/FineChannel.js",
    "content": "import AbstractChannel from './AbstractChannel.js';\nimport CoarseChannel from './CoarseChannel.js';\n/** @import Fixture from './Fixture.js' */\n\n/**\n * Represents a finer channel of a 16+ bit channel.\n * Also called LSB (least significant byte) channel.\n * @extends AbstractChannel\n */\nclass FineChannel extends AbstractChannel {\n  /**\n   * Creates a new FineChannel instance.\n   * @param {string} key The fine channel alias as defined in the coarse channel.\n   * @param {CoarseChannel} coarseChannel The coarse (MSB) channel.\n   */\n  constructor(key, coarseChannel) {\n    super(key);\n    this._coarseChannel = coarseChannel;\n  }\n\n  /**\n   * @returns {CoarseChannel} The coarse (MSB) channel.\n   */\n  get coarseChannel() {\n    return this._coarseChannel;\n  }\n\n  /**\n   * @returns {CoarseChannel | FineChannel} The next coarser channel. May also be a fine channel, if this fine channel's resolution is 24bit or higher.\n   */\n  get coarserChannel() {\n    return this.resolution === CoarseChannel.RESOLUTION_16BIT ? this.coarseChannel : this.coarseChannel.fineChannels[this.resolution - 3];\n  }\n\n  /**\n   * Overrides [`AbstractChannel.name`]{@link AbstractChannel#name}.\n   * @returns {string} A generated channel name, based upon the coarse channel's name.\n   */\n  get name() {\n    const suffix = this.resolution > CoarseChannel.RESOLUTION_16BIT ? `^${this.resolution - 1}` : '';\n    return `${this.coarseChannel.name} fine${suffix}`;\n  }\n\n  /**\n   * Overrides [`AbstractChannel.fixture`]{@link AbstractChannel#fixture}.\n   * @returns {Fixture} The fixture this channel belongs to.\n   */\n  get fixture() {\n    return this.coarseChannel.fixture;\n  }\n\n  /**\n   * @returns {Resolution} The resolution of this fine channel. E.g. 2 (16bit) for the first fine channel, 3 (24bit) for the second fine channel, etc.\n   */\n  get resolution() {\n    return this._coarseChannel.fineChannelAliases.indexOf(this.key) + 2;\n  }\n\n  /**\n   * @returns {number} The DMX value (from 0 to 255) this channel should be set to by default.\n   */\n  get defaultValue() {\n    return this._coarseChannel.getDefaultValueWithResolution(this.resolution) % 256;\n  }\n}\n\nexport default FineChannel;\n"
  },
  {
    "path": "lib/model/Fixture.js",
    "content": "import cacheResult from '../cache-result.js';\nimport CoarseChannel from './CoarseChannel.js';\nimport FineChannel from './FineChannel.js';\nimport Matrix from './Matrix.js';\nimport Meta from './Meta.js';\nimport Mode from './Mode.js';\nimport NullChannel from './NullChannel.js';\nimport Physical from './Physical.js';\nimport SwitchingChannel from './SwitchingChannel.js';\nimport TemplateChannel from './TemplateChannel.js';\nimport Wheel from './Wheel.js';\n/** @import AbstractChannel from './AbstractChannel.js' */\n/** @import Capability from './Capability.js' */\n/** @import Manufacturer from './Manufacturer.js' */\n\n/*\n  benchmark results for accessing fix.physical (10,000,000 iterations):\n  - without cache: ~1.9s\n  - with cache: ~0.52s (nearly 4 times faster!)\n  => that proves why caching, even for these small objects, is useful\n\n  Code:\n    const benchmarkIterations = 10000000;\n    function benchmark() {\n      const t0 = process.hrtime();\n\n      for (let i = 0; i < benchmarkIterations; i++) {\n        fix1.physical;\n      }\n\n      const deltaT = process.hrtime(t0);\n\n      console.log(deltaT);\n    }\n*/\n\n/**\n * A physical DMX device.\n */\nclass Fixture {\n  /**\n   * Create a new Fixture instance.\n   * @param {Manufacturer} manufacturer A Manufacturer instance.\n   * @param {string} key The fixture's unique key. Equals to filename without '.json'.\n   * @param {object} jsonObject The fixture's parsed JSON data.\n   */\n  constructor(manufacturer, key, jsonObject) {\n    this._manufacturer = manufacturer;\n    this._key = key;\n    this._jsonObject = jsonObject;\n  }\n\n  /**\n   * @returns {Manufacturer} The fixture's manufacturer.\n   */\n  get manufacturer() {\n    return this._manufacturer;\n  }\n\n  /**\n   * @returns {string} The fixture's unique key. Equals to filename without '.json'.\n   */\n  get key() {\n    return this._key;\n  }\n\n  /**\n   * @returns {object} The fixture's parsed JSON data.\n   */\n  get jsonObject() {\n    return this._jsonObject;\n  }\n\n  /**\n   * @returns {string} An URL pointing to the fixture's page on the Open Fixture Library website.\n   */\n  get url() {\n    const websiteUrl = process.env.WEBSITE_URL || 'https://open-fixture-library.org/';\n    return `${websiteUrl}${this.manufacturer.key}/${this.key}`;\n  }\n\n  /**\n   * @returns {string} The fixture's product name.\n   */\n  get name() {\n    return this._jsonObject.name; // required\n  }\n\n  /**\n   * @returns {boolean} Whether a short name is defined for this fixture.\n   */\n  get hasShortName() {\n    return 'shortName' in this._jsonObject;\n  }\n\n  /**\n   * @returns {string} A globally unique and as short as possible product name, defaults to name.\n   */\n  get shortName() {\n    return this._jsonObject.shortName || this._jsonObject.name;\n  }\n\n  /**\n   * @returns {string[]} The fixture's categories with the most applicable one first.\n   */\n  get categories() {\n    return this._jsonObject.categories; // required\n  }\n\n  /**\n   * @returns {string} The fixture's most applicable category. Equals to first item of categories.\n   */\n  get mainCategory() {\n    return this.categories[0];\n  }\n\n  /**\n   * @returns {Meta} A Meta instance providing information like author or create date.\n   */\n  get meta() {\n    return cacheResult(this, 'meta', new Meta(this._jsonObject.meta));\n  }\n\n  /**\n   * @returns {boolean} Whether a comment is defined for this fixture.\n   */\n  get hasComment() {\n    return 'comment' in this._jsonObject;\n  }\n\n  /**\n   * @returns {string} A comment about the fixture (often a note about an incorrectness in the manual). Defaults to an empty string.\n   */\n  get comment() {\n    return this._jsonObject.comment || '';\n  }\n\n  /**\n   * @returns {string | null} A string describing the help that is needed for this fixture, or null if no help is needed.\n   */\n  get helpWanted() {\n    return this._jsonObject.helpWanted || null;\n  }\n\n  /**\n   * @returns {boolean} True if help is needed in this fixture (maybe in a capability), false otherwise.\n   */\n  get isHelpWanted() {\n    return this.helpWanted !== null || this.isCapabilityHelpWanted;\n  }\n\n  /**\n   * @returns {boolean} True if help is needed in a capability, false otherwise.\n   */\n  get isCapabilityHelpWanted() {\n    return cacheResult(this, 'isCapabilityHelpWanted', this.allChannels.some(\n      (channel) => channel.isHelpWanted,\n    ));\n  }\n\n  /**\n   * @returns {Record<string, string[]> | null} An object with URL arrays, organized by link type, or null if no links are available for this fixture.\n   */\n  get links() {\n    return this._jsonObject.links || null;\n  }\n\n  /**\n   * @param {string} type The type of the links that should be returned.\n   * @returns {string[]} An array of URLs of the specified type (may be empty).\n   */\n  getLinksOfType(type) {\n    if (this.links === null) {\n      return [];\n    }\n\n    return this.links[type] || [];\n  }\n\n  /**\n   * @returns {object | null} Information about the RDM functionality of this fixture. Defaults to null.\n   * @property {number} modelId The RDM model/product id of the fixture, given in decimal format.\n   * @property {string | null} softwareVersion The software version used as reference in this fixture definition.\n   */\n  get rdm() {\n    return this._jsonObject.rdm || null;\n  }\n\n  /**\n   * @returns {Physical | null} The general physical information for the fixture, may be overridden by modes.\n   */\n  get physical() {\n    if ('physical' in this._jsonObject) {\n      return cacheResult(this, 'physical', new Physical(this._jsonObject.physical));\n    }\n\n    return cacheResult(this, 'physical', null);\n  }\n\n  /**\n   * @returns {Matrix | null} The matrix information for this fixture.\n   */\n  get matrix() {\n    if ('matrix' in this._jsonObject) {\n      return cacheResult(this, 'matrix', new Matrix(this._jsonObject.matrix));\n    }\n\n    return cacheResult(this, 'matrix', null);\n  }\n\n  /**\n   * @returns {Wheel[]} The fixture's wheels as {@link Wheel} instances.\n   */\n  get wheels() {\n    const wheels = Object.entries(this._jsonObject.wheels || {}).map(\n      ([wheelName, wheelJson]) => new Wheel(wheelName, wheelJson),\n    );\n    return cacheResult(this, 'wheels', wheels);\n  }\n\n  /**\n   * @private\n   * @returns {Record<string, Wheel>} This fixture's wheel names pointing to the respective Wheel instance.\n   */\n  get _wheelByName() {\n    return cacheResult(this, '_wheelByName', Object.fromEntries(\n      this.wheels.map((wheel) => [wheel.name, wheel]),\n    ));\n  }\n\n  /**\n   * @param {string} wheelName The name of the wheel.\n   * @returns {Wheel | null} The wheel with the given name, or null if no wheel with the given name exists.\n   */\n  getWheelByName(wheelName) {\n    return this._wheelByName[wheelName] || null;\n  }\n\n  /**\n   * @returns {Record<string, string>} Channel keys from {@link Fixture#allChannelKeys} pointing to unique versions of their channel names.\n   */\n  get uniqueChannelNames() {\n    const uniqueChannelNames = {};\n\n    const names = this.allChannels.map((channel) => channel.name);\n\n    for (let index = 0; index < names.length; index++) {\n      const originalName = names[index];\n\n      // make unique by appending ' 2', ' 3', ...\n      let duplicates = 1;\n      while (names.indexOf(names[index]) !== index) {\n        duplicates++;\n        names[index] = `${originalName} ${duplicates}`;\n      }\n\n      // save unique name\n      uniqueChannelNames[this.allChannelKeys[index]] = names[index];\n    }\n\n    return cacheResult(this, 'uniqueChannelNames', uniqueChannelNames);\n  }\n\n  /**\n   * @returns {string[]} Coarse channels from the fixture definition's `availableChannels` section. Ordered by appearance.\n   */\n  get availableChannelKeys() {\n    return cacheResult(this, 'availableChannelKeys', Object.keys(this._jsonObject.availableChannels || {}));\n  }\n\n  /**\n   * @returns {CoarseChannel[]} Coarse channels from the fixture definition's `availableChannels` section. Ordered by appearance.\n   */\n  get availableChannels() {\n    return cacheResult(this, 'availableChannels', this.availableChannelKeys.map(\n      (channelKey) => new CoarseChannel(channelKey, this._jsonObject.availableChannels[channelKey], this),\n    ));\n  }\n\n  /**\n   * @returns {string[]} Coarse channels' keys, including matrix channels' keys. If possible, ordered by appearance.\n   */\n  get coarseChannelKeys() {\n    return cacheResult(this, 'coarseChannelKeys', this.coarseChannels.map(\n      (channel) => channel.key,\n    ));\n  }\n\n  /**\n   * @returns {CoarseChannel[]} Coarse channels, including matrix channels. If possible, ordered by appearance.\n   */\n  get coarseChannels() {\n    return cacheResult(this, 'coarseChannels', this.allChannels.filter(\n      (channel) => channel instanceof CoarseChannel,\n    ));\n  }\n\n  /**\n   * @returns {string[]} All fine channels' aliases, including matrix fine channels' aliases. If possible, ordered by appearance.\n   */\n  get fineChannelAliases() {\n    return cacheResult(this, 'fineChannelAliases', this.fineChannels.map(\n      (channel) => channel.key,\n    ));\n  }\n\n  /**\n   * @returns {FineChannel[]} All fine channels, including matrix fine channels. If possible, ordered by appearance.\n   */\n  get fineChannels() {\n    return cacheResult(this, 'fineChannels', this.allChannels.filter(\n      (channel) => channel instanceof FineChannel,\n    ));\n  }\n\n  /**\n   * @returns {string[]} All switching channels' aliases, including matrix switching channels' aliases. If possible, ordered by appearance.\n   */\n  get switchingChannelAliases() {\n    return cacheResult(this, 'switchingChannelAliases', this.switchingChannels.map(\n      (channel) => channel.key,\n    ));\n  }\n\n  /**\n   * @returns {SwitchingChannel[]} All switching channels, including matrix switching channels. If possible, ordered by appearance.\n   */\n  get switchingChannels() {\n    return cacheResult(this, 'switchingChannels', this.allChannels.filter(\n      (channel) => channel instanceof SwitchingChannel,\n    ));\n  }\n\n  /**\n   * Template channels are used to automatically generate channels.\n   * @returns {string[]} All template channel keys from the fixture definition's `templateChannels` section. Ordered by appearance.\n   */\n  get templateChannelKeys() {\n    return Object.keys(this._jsonObject.templateChannels || {});\n  }\n\n  /**\n   * Template channels are used to automatically generate channels.\n   * @returns {TemplateChannel[]} TemplateChannel instances for all template channels from the fixture definition's `templateChannels` section. Ordered by appearance.\n   */\n  get templateChannels() {\n    return cacheResult(this, 'templateChannels', this.templateChannelKeys.map(\n      (key) => new TemplateChannel(key, this._jsonObject.templateChannels[key], this),\n    ));\n  }\n\n  /**\n   * @private\n   * @returns {Record<string, TemplateChannel>} This fixture's template channel keys pointing to the respective template channel.\n   */\n  get _templateChannelByKey() {\n    return cacheResult(this, '_templateChannelByKey', Object.fromEntries(\n      this.templateChannels.map((channel) => [channel.key, channel]),\n    ));\n  }\n\n  /**\n   * Searches the template channel with the given key. Fine and switching template channel aliases *can't* be found.\n   * @param {string} channelKey The template channel's key\n   * @returns {TemplateChannel | null} The corresponding template channel.\n   */\n  getTemplateChannelByKey(channelKey) {\n    return this._templateChannelByKey[channelKey] || null;\n  }\n\n  /**\n   * @returns {string[]} Keys of all resolved matrix channels.\n   */\n  get matrixChannelKeys() {\n    return cacheResult(this, 'matrixChannelKeys', this.matrixChannels.map(\n      (channel) => channel.key,\n    ));\n  }\n\n  /**\n   * @returns {AbstractChannel[]} All (resolved) channels with `pixelKey` information (including fine and switching channels).\n   */\n  get matrixChannels() {\n    if (this.matrix === null) {\n      return cacheResult(this, 'matrixChannels', []);\n    }\n\n    return cacheResult(this, 'matrixChannels', this.allChannels.filter(\n      (channel) => channel.pixelKey !== null,\n    ));\n  }\n\n  /**\n   * @returns {string[]} All null channels' keys.\n   */\n  get nullChannelKeys() {\n    return this.nullChannels.map((channel) => channel.key);\n  }\n\n  /**\n   * @returns {NullChannel[]} Automatically generated null channels.\n   */\n  get nullChannels() {\n    // we only need to create as many NullChannels as in the mode with the most null channels\n    // e.g. Mode 1: 1x null, Mode 2: 3x null, Mode 3: 2x null => 3 NullChannels\n    const maxNullPerMode = Math.max(...this.modes.map((mode) => mode.nullChannelCount));\n    const nullChannels = Array.from({ length: maxNullPerMode }, () => new NullChannel(this));\n\n    return cacheResult(this, 'nullChannels', nullChannels);\n  }\n\n  /**\n   * @returns {string[]} All channel keys used in this fixture, including resolved matrix channels' keys. If possible, ordered by appearance.\n   */\n  get allChannelKeys() {\n    return cacheResult(this, 'allChannelKeys', Object.keys(this.allChannelsByKey));\n  }\n\n  /**\n   * @returns {AbstractChannel[]} All channels used in this fixture, including resolved matrix channels. If possible, ordered by appearance.\n   */\n  get allChannels() {\n    return cacheResult(this, 'allChannels', Object.values(this.allChannelsByKey));\n  }\n\n  /**\n   * @returns {Record<string, AbstractChannel>} All channel keys used in this fixture pointing to the respective channel, including matrix channels. If possible, ordered by appearance.\n   */\n  get allChannelsByKey() {\n    const allChannels = [\n      ...this.availableChannels.flatMap((mainChannel) => [\n        mainChannel,\n        ...mainChannel.fineChannels,\n        ...mainChannel.switchingChannels,\n      ]),\n      ...this.nullChannels,\n    ];\n\n    const allChannelsByKey = Object.fromEntries(\n      allChannels.map((channel) => [channel.key, channel]),\n    );\n\n    const allMatrixChannelsByKey = Object.fromEntries(\n      this.templateChannels\n        .flatMap((templateChannel) => templateChannel.createMatrixChannels())\n        .map((matrixChannel) => [matrixChannel.key, matrixChannel]),\n    );\n\n    for (let matrixChannel of Object.values(allMatrixChannelsByKey)) {\n      if (matrixChannel.key in allChannelsByKey) {\n        // matrix channel is overridden by an available channel\n        const overrideChannel = allChannelsByKey[matrixChannel.key];\n        overrideChannel.pixelKey = matrixChannel.pixelKey;\n\n        // move channel to the place where the matrix channel would have been inserted\n        delete allChannelsByKey[matrixChannel.key];\n        matrixChannel = overrideChannel;\n      }\n\n      // check if matrix channel is used in a mode's channel list\n      // (maybe indirect in switching channels)\n      const matrixChannelUsed = this.modes.some(\n        (mode) => mode.channelKeys.some((channelKey) => {\n          if (matrixChannel.key === channelKey) {\n            // matrix channel used directly\n            return true;\n          }\n\n          // matrix channel used in a switching channel\n          const otherChannel = allChannelsByKey[channelKey] || allMatrixChannelsByKey[channelKey];\n          return otherChannel instanceof SwitchingChannel && otherChannel.switchToChannelKeys.includes(matrixChannel.key);\n        }),\n      );\n\n      if (matrixChannelUsed) {\n        allChannelsByKey[matrixChannel.key] = matrixChannel;\n      }\n    }\n\n    return cacheResult(this, 'allChannelsByKey', allChannelsByKey);\n  }\n\n  /**\n   * @param {string} key The channel's key.\n   * @returns {AbstractChannel | null} The found channel, null if not found.\n   */\n  getChannelByKey(key) {\n    return this.allChannelsByKey[key] || null;\n  }\n\n  /**\n   * @returns {Capability[]} All available channels' and template channels' capabilities.\n   */\n  get capabilities() {\n    const channels = [...this.availableChannels, ...this.templateChannels];\n    const capabilities = channels.flatMap((channel) => channel.capabilities);\n    return cacheResult(this, 'capabilities', capabilities);\n  }\n\n  /**\n   * @returns {Mode[]} The fixture's modes.\n   */\n  get modes() {\n    return cacheResult(this, 'modes', this._jsonObject.modes.map(\n      (jsonMode) => new Mode(jsonMode, this),\n    ));\n  }\n}\n\nexport default Fixture;\n"
  },
  {
    "path": "lib/model/Manufacturer.js",
    "content": "/**\n * A company or brand that produces fixtures. A fixture is associated to exactly one manufacturer.\n */\nclass Manufacturer {\n  /**\n   * Creates a new Manufacturer instance.\n   * @param {string} key The manufacturer key. Equals to directory name in the fixtures directory.\n   * @param {object} jsonObject The manufacturer's JSON object.\n   */\n  constructor(key, jsonObject) {\n    this.key = key;\n    this._jsonObject = jsonObject;\n  }\n\n  /**\n   * @returns {string} The manufacturer's display name. Often used as prefix of fixture names, e.g. \"cameo\" + \"Hydrabeam 100\".\n   */\n  get name() {\n    return this._jsonObject.name;\n  }\n\n  /**\n   * @returns {string} An additional description or explanation, if the name doesn't give enough information. Defaults to an empty string.\n   */\n  get comment() {\n    return this._jsonObject.comment || '';\n  }\n\n  /**\n   * @returns {boolean} Whether this manufacturer has a comment.\n   */\n  get hasComment() {\n    return 'comment' in this._jsonObject;\n  }\n\n  /**\n   * @returns {string | null} An URL pointing to the manufacturer's website (with fixture product pages).\n   */\n  get website() {\n    return this._jsonObject.website || null;\n  }\n\n  /**\n   * @returns {number | null} The id associated to this manufacturer in the RDM protocol.\n   */\n  get rdmId() {\n    return this._jsonObject.rdmId || null;\n  }\n}\n\nexport default Manufacturer;\n"
  },
  {
    "path": "lib/model/Matrix.js",
    "content": "import cacheResult from '../cache-result.js';\n\n/**\n * Contains information of how the pixels in a 1-, 2- or 3-dimensional space are arranged and named.\n */\nclass Matrix {\n  /**\n   * @param {object} jsonObject The fixture's JSON object containing the matrix information.\n   */\n  constructor(jsonObject) {\n    this._jsonObject = jsonObject;\n  }\n\n  /**\n   * @returns {object} The fixture's JSON object containing the matrix information.\n   */\n  get jsonObject() {\n    return this._jsonObject;\n  }\n\n  /**\n   * @returns {number[]} Amount of pixels in X, Y and Z direction. A horizontal bar with 4 LEDs would be `[4, 1, 1]`, a 5x5 pixel head would be `[5, 5, 1]`.\n   * @throws {ReferenceError} If neither `pixelCount` nor `pixelKeys` are defined in the matrix JSON object.\n   */\n  get pixelCount() {\n    if ('pixelCount' in this._jsonObject) {\n      return cacheResult(this, 'pixelCount', this._jsonObject.pixelCount);\n    }\n\n    if ('pixelKeys' in this._jsonObject) {\n      const xyz = [1, 1, this.pixelKeyStructure.length];\n\n      for (const yItems of this.pixelKeyStructure) {\n        xyz[1] = Math.max(xyz[1], yItems.length);\n\n        for (const xItems of yItems) {\n          xyz[0] = Math.max(xyz[0], xItems.length);\n        }\n      }\n\n      return cacheResult(this, 'pixelCount', xyz);\n    }\n\n    // if we didn't catch this case, an endless loop could be created\n    throw new ReferenceError('Either pixelCount or pixelKeys has to be specified in a fixture\\'s matrix object.');\n  }\n\n  /**\n   * @returns {number} Amount of pixels in X direction.\n   */\n  get pixelCountX() {\n    return this.pixelCount[0];\n  }\n\n  /**\n   * @returns {number} Amount of pixels in Y direction.\n   */\n  get pixelCountY() {\n    return this.pixelCount[1];\n  }\n\n  /**\n   * @returns {number} Amount of pixels in Z direction.\n   */\n  get pixelCountZ() {\n    return this.pixelCount[2];\n  }\n\n  /**\n   * @returns {string[]} Contains each of 'X', 'Y', 'Z' if its respective axis is defined (= if its `pixelCount` is > 1).\n   */\n  get definedAxes() {\n    const definedAxes = [];\n\n    if (this.pixelCountX > 1) {\n      definedAxes.push('X');\n    }\n    if (this.pixelCountY > 1) {\n      definedAxes.push('Y');\n    }\n    if (this.pixelCountZ > 1) {\n      definedAxes.push('Z');\n    }\n\n    return cacheResult(this, 'definedAxes', definedAxes);\n  }\n\n  /**\n   * @returns {string[][][]} Pixel keys by Z, Y and X position.\n   * @throws {ReferenceError} if neither `pixelCount` nor `pixelKeys` are defined in the matrix JSON object.\n   */\n  get pixelKeyStructure() {\n    if ('pixelKeys' in this._jsonObject) {\n      return cacheResult(this, 'pixelKeyStructure', this._jsonObject.pixelKeys);\n    }\n\n    if ('pixelCount' in this._jsonObject) {\n      return cacheResult(this, 'pixelKeyStructure', this._getPixelDefaultKeys());\n    }\n\n    // if we didn't catch this case, an endless loop could be created\n    throw new ReferenceError('Either pixelCount or pixelKeys has to be specified in a fixture\\'s matrix object.');\n  }\n\n  /**\n   * Generate default keys for all pixels.\n   * @private\n   * @returns {string[][][]} Default pixel keys by Z, Y and X position.\n   */\n  _getPixelDefaultKeys() {\n    const zItems = [];\n\n    for (let z = 1; z <= this.pixelCountZ; z++) {\n      const yItems = [];\n\n      for (let y = 1; y <= this.pixelCountY; y++) {\n        const xItems = [];\n\n        for (let x = 1; x <= this.pixelCountX; x++) {\n          xItems.push(this._getPixelDefaultKey(x, y, z));\n        }\n\n        yItems.push(xItems);\n      }\n\n      zItems.push(yItems);\n    }\n\n    return zItems;\n  }\n\n  /**\n   * Generate default name based on defined axes and given position if no custom names are set via `pixelKeys`.\n   *\n   * | Dimension | Default pixelKey |\n   * | --------- | ---------------- |\n   * | 1D        | `\"$number\"`      |\n   * | 2D        | `\"($x, $y)\"`     |\n   * | 3D        | `\"($x, $y, $z)\"` |\n   *\n   * @private\n   * @param {number} x Position of pixel in X direction.\n   * @param {number} y Position of pixel in Y direction.\n   * @param {number} z Position of pixel in Z direction.\n   * @returns {string} The pixel's default key.\n   * @throws {RangeError} If {@link Matrix#definedAxes}.length is not 1, 2 or 3.\n   */\n  _getPixelDefaultKey(x, y, z) {\n    switch (this.definedAxes.length) {\n      case 1: {\n        return Math.max(x, y, z).toString();\n      }\n      case 2: {\n        const first = this.definedAxes.includes('X') ? x : y;\n        const last = this.definedAxes.includes('Y') ? y : z;\n        return `(${first}, ${last})`;\n      }\n      case 3: {\n        return `(${x}, ${y}, ${z})`;\n      }\n      default: {\n        throw new RangeError('Only 1, 2 or 3 axes can be defined.');\n      }\n    }\n  }\n\n  /**\n   * @returns {string[]} All pixelKeys, ordered alphanumerically (1 < 2 < 10 < alice < bob < carol)\n   */\n  get pixelKeys() {\n    const pixelKeys = Object.keys(this.pixelKeyPositions).toSorted(\n      (a, b) => a.toString().localeCompare(b, undefined, { numeric: true }),\n    );\n\n    return cacheResult(this, 'pixelKeys', pixelKeys);\n  }\n\n  /**\n   * Sorts the pixelKeys by given X/Y/Z order. Order of the parameters equals the order in a `repeatFor`'s \"eachPixelXYZ\".\n   * @param {'X' | 'Y' | 'Z'} firstAxis Axis with highest ordering.\n   * @param {'X' | 'Y' | 'Z'} secondAxis Axis with middle ordering.\n   * @param {'X' | 'Y' | 'Z'} thirdAxis Axis with lowest ordering.\n   * @returns {string[]} All pixelKeys ordered by given axis order.\n   */\n  getPixelKeysByOrder(firstAxis, secondAxis, thirdAxis) {\n    const axisToPosIndex = { X: 0, Y: 1, Z: 2 };\n    const firstPosIndex = axisToPosIndex[firstAxis];\n    const secondPosIndex = axisToPosIndex[secondAxis];\n    const thirdPosIndex = axisToPosIndex[thirdAxis];\n\n    return this.pixelKeys.toSorted((keyA, keyB) => {\n      const [posA, posB] = [this.pixelKeyPositions[keyA], this.pixelKeyPositions[keyB]];\n\n      if (posA[thirdPosIndex] !== posB[thirdPosIndex]) {\n        return posA[thirdPosIndex] - posB[thirdPosIndex];\n      }\n      if (posA[secondPosIndex] !== posB[secondPosIndex]) {\n        return posA[secondPosIndex] - posB[secondPosIndex];\n      }\n      return posA[firstPosIndex] - posB[firstPosIndex];\n    });\n  }\n\n  /**\n   * @returns {Record<string, number[]>} Each pixelKey pointing to an array of its X/Y/Z position\n   */\n  get pixelKeyPositions() {\n    const pixelKeyPositions = {};\n\n    for (let z = 0; z < this.pixelCountZ; z++) {\n      for (let y = 0; y < this.pixelCountY; y++) {\n        for (let x = 0; x < this.pixelCountX; x++) {\n          if (this.pixelKeyStructure[z][y][x] !== null) {\n            pixelKeyPositions[this.pixelKeyStructure[z][y][x]] = [x + 1, y + 1, z + 1];\n          }\n        }\n      }\n    }\n\n    return cacheResult(this, 'pixelKeyPositions', pixelKeyPositions);\n  }\n\n  /**\n   * @returns {string[]} All available pixel group keys, ordered by appearance.\n   */\n  get pixelGroupKeys() {\n    return cacheResult(this, 'pixelGroupKeys', Object.keys(this.pixelGroups));\n  }\n\n  /**\n   * @returns {Record<string, string[]>} Key is the group key, value is an array of pixel keys.\n   */\n  get pixelGroups() {\n    const pixelGroups = {};\n\n    if ('pixelGroups' in this._jsonObject) {\n      for (const [groupKey, group] of Object.entries(this._jsonObject.pixelGroups)) {\n        if (Array.isArray(group)) {\n          // pixel keys specified directly\n          pixelGroups[groupKey] = group;\n        }\n        else if (group === 'all') {\n          pixelGroups[groupKey] = this.pixelKeys;\n        }\n        else {\n          // pixel key constraints\n          const constraints = convertConstraintsToFunctions(group);\n          const pixelKeys = 'name' in group ? this.pixelKeys : this.getPixelKeysByOrder('X', 'Y', 'Z');\n\n          pixelGroups[groupKey] = pixelKeys.filter(\n            (key) => this._pixelKeyFulfillsConstraints(key, constraints),\n          );\n        }\n      }\n    }\n\n    return cacheResult(this, 'pixelGroups', pixelGroups);\n  }\n\n  /**\n   * @param {string} pixelKey The pixel key to check against the constraints.\n   * @param {object} constraints The constraints to apply.\n   * @returns {boolean} True if the pixel key fulfills all constraints, false otherwise.\n   */\n  _pixelKeyFulfillsConstraints(pixelKey, constraints) {\n    const position = this.pixelKeyPositions[pixelKey];\n\n    const numberConstraintsFulfilled = ['x', 'y', 'z'].every((axis, axisIndex) => {\n      const axisPos = position[axisIndex];\n\n      return constraints[axis].every((constraintFunction) => constraintFunction(axisPos));\n    });\n\n    const stringConstraintsFulfilled = constraints.name.every(\n      (constraintFunction) => constraintFunction(pixelKey),\n    );\n\n    return numberConstraintsFulfilled && stringConstraintsFulfilled;\n  }\n}\n\n/**\n * @ignore\n * @param {Record<string, string[]>} constraints The constraints to apply.\n * @returns {object} The constraints converted to functions.\n */\nfunction convertConstraintsToFunctions(constraints) {\n  const constraintFunctions = {};\n\n  // number constraints\n  for (const axis of ['x', 'y', 'z']) {\n    constraintFunctions[axis] = (constraints[axis] || []).map(\n      (constraint) => convertNumberConstraintToFunction(constraint),\n    );\n  }\n\n  constraintFunctions.name = (constraints.name || []).map(\n    (pattern) => (name) => new RegExp(pattern).test(name),\n  );\n\n  return constraintFunctions;\n}\n\n/**\n * @ignore\n * @param {string} constraint The number constraint to apply.\n * @returns {function(number): boolean} The constraint converted to a function.\n */\nfunction convertNumberConstraintToFunction(constraint) {\n  if (constraint.startsWith('=')) {\n    const eqPos = Number.parseInt(constraint.slice(1), 10);\n    return (position) => position === eqPos;\n  }\n\n  if (constraint.startsWith('>=')) {\n    const minPos = Number.parseInt(constraint.slice(2), 10);\n    return (position) => position >= minPos;\n  }\n\n  if (constraint.startsWith('<=')) {\n    const maxPos = Number.parseInt(constraint.slice(2), 10);\n    return (position) => position <= maxPos;\n  }\n\n  constraint = constraint.replace(/^even$/, '2n');\n  constraint = constraint.replace(/^odd$/, '2n+1');\n\n  const match = constraint.match(/^(\\d+)n(?:\\+(\\d+)|)$/);\n  if (match !== null) {\n    const divisor = Number.parseInt(match[1], 10);\n    const remainder = Number.parseInt(match[2] || '0', 10);\n    return (position) => position % divisor === remainder;\n  }\n\n  throw new Error(`Invalid pixel key constraint '${constraint}'.`);\n}\n\nexport default Matrix;\n"
  },
  {
    "path": "lib/model/Meta.js",
    "content": "/**\n * Information about a fixture's author and history.\n */\nclass Meta {\n  /**\n   * Creates a new Meta instance.\n   * @param {object} jsonObject A meta object from the fixture's JSON data.\n   */\n  constructor(jsonObject) {\n    this._jsonObject = jsonObject;\n  }\n\n  /**\n   * @returns {string[]} Names of people who contributed to this fixture.\n   */\n  get authors() {\n    return this._jsonObject.authors;\n  }\n\n  /**\n   * @returns {Date} When this fixture was created. Might not refer to the creation in OFL, but in the lighting software from which this fixture was imported.\n   */\n  get createDate() {\n    return new Date(this._jsonObject.createDate);\n  }\n\n  /**\n   * @returns {Date} When this fixture was changed the last time. Might not refer to a modification in OFL, but in the lighting software from which this fixture was imported.\n   */\n  get lastModifyDate() {\n    return new Date(this._jsonObject.lastModifyDate);\n  }\n\n  /**\n   * @returns {string | null} The key of the plugin with which this fixture was imported. Null if it's not imported.\n   */\n  get importPlugin() {\n    return 'importPlugin' in this._jsonObject ? this._jsonObject.importPlugin.plugin : null;\n  }\n\n  /**\n   * @returns {Date | null} When this fixture was imported. Null if it's not imported.\n   */\n  get importDate() {\n    return 'importPlugin' in this._jsonObject ? new Date(this._jsonObject.importPlugin.date) : null;\n  }\n\n  /**\n   * @returns {string | null} A comment further describing the import process. Null if it's not imported.\n   */\n  get importComment() {\n    return 'importPlugin' in this._jsonObject ? (this._jsonObject.importPlugin.comment || '') : null;\n  }\n\n  /**\n   * @returns {boolean} Whether there is an import comment. Always false if it's not imported.\n   */\n  get hasImportComment() {\n    return this.importPlugin !== null && 'comment' in this._jsonObject.importPlugin;\n  }\n}\n\nexport default Meta;\n"
  },
  {
    "path": "lib/model/Mode.js",
    "content": "import cacheResult from '../cache-result.js';\nimport Physical from './Physical.js';\nimport SwitchingChannel from './SwitchingChannel.js';\nimport TemplateChannel from './TemplateChannel.js';\n/** @import AbstractChannel from './AbstractChannel.js' */\n/** @import Fixture from './Fixture.js' */\n\n/**\n * A fixture's configuration that enables a fixed set of channels and channel order.\n */\nclass Mode {\n  /**\n   * Creates a new Mode instance\n   * @param {object} jsonObject The mode object from the fixture's JSON data.\n   * @param {Fixture} fixture The fixture this mode is associated to.\n   */\n  constructor(jsonObject, fixture) {\n    this._jsonObject = jsonObject;\n    this._fixture = fixture;\n  }\n\n  /**\n   * @returns {object} The JSON data representing this mode. It's a fragment of a fixture's JSON data.\n   */\n  get jsonObject() {\n    return this._jsonObject;\n  }\n\n  /**\n   * @returns {Fixture} The fixture this mode belongs to.\n   */\n  get fixture() {\n    return this._fixture;\n  }\n\n  /**\n   * @returns {string} The mode's name from the JSON data.\n   */\n  get name() {\n    return this._jsonObject.name; // required\n  }\n\n  /**\n   * @returns {string} A shorter mode name from the JSON data. Defaults to the normal name.\n   */\n  get shortName() {\n    return this._jsonObject.shortName || this._jsonObject.name;\n  }\n\n  /**\n   * @returns {boolean} Whether this mode has a short name set in the JSON data.\n   */\n  get hasShortName() {\n    return 'shortName' in this._jsonObject;\n  }\n\n  /**\n   * @returns {number | null} The index used in the RDM protocol to reference this mode. Defaults to null.\n   */\n  get rdmPersonalityIndex() {\n    return this._jsonObject.rdmPersonalityIndex || null;\n  }\n\n  /**\n   * @returns {Physical | null} Extend the fixture's physical data with this physical data object when this mode is activated. Defaults to null.\n   */\n  get physicalOverride() {\n    if ('physical' in this._jsonObject) {\n      return cacheResult(this, 'physicalOverride', new Physical(this._jsonObject.physical));\n    }\n\n    return cacheResult(this, 'physicalOverride', null);\n  }\n\n  /**\n   * @returns {Physical | null} Fixture's physical with mode's physical override (if present) applied on. Null if neither fixture nor mode define physical data.\n   */\n  get physical() {\n    if (this.fixture.physical === null) {\n      return cacheResult(this, 'physical', this.physicalOverride);\n    }\n\n    if (this.physicalOverride === null) {\n      return cacheResult(this, 'physical', this.fixture.physical);\n    }\n\n    const fixturePhysical = this.fixture.physical.jsonObject;\n    const physicalOverride = this._jsonObject.physical;\n    const physicalData = { ...fixturePhysical, ...physicalOverride };\n\n    for (const property of ['bulb', 'lens', 'matrixPixels']) {\n      if (property in physicalData) {\n        physicalData[property] = {\n          ...fixturePhysical[property],\n          ...physicalOverride[property],\n        };\n      }\n    }\n\n    return cacheResult(this, 'physical', new Physical(physicalData));\n  }\n\n  /**\n   * @returns {string[]} The mode's channel keys. The count and position equals to actual DMX channel count and position.\n   */\n  get channelKeys() {\n    const channelKeys = this._jsonObject.channels.flatMap((rawReference) => {\n      if (rawReference !== null && rawReference.insert === 'matrixChannels') {\n        // channel insert block\n        return this._getMatrixChannelKeysFromInsertBlock(rawReference);\n      }\n\n      // normal channel key\n      return rawReference;\n    });\n    return cacheResult(this, 'channelKeys', channelKeys);\n  }\n\n  /**\n   * @returns {number} The number of null channels used in this mode.\n   */\n  get nullChannelCount() {\n    return this.channelKeys.filter((channelKey) => channelKey === null).length;\n  }\n\n  /**\n   * Resolves the matrix channel insert block into a list of channel keys\n   * @private\n   * @param {object} channelInsert The JSON channel insert block\n   * @returns {string[]} The resolved channel keys\n   */\n  _getMatrixChannelKeysFromInsertBlock(channelInsert) {\n    const pixelKeys = this._getRepeatForPixelKeys(channelInsert.repeatFor);\n\n    const channelKeys = [];\n    if (channelInsert.channelOrder === 'perPixel') {\n      for (const pixelKey of pixelKeys) {\n        for (const templateChannelKey of channelInsert.templateChannels) {\n          channelKeys.push(TemplateChannel.resolveTemplateString(templateChannelKey, {\n            pixelKey,\n          }));\n        }\n      }\n    }\n    else if (channelInsert.channelOrder === 'perChannel') {\n      for (const templateChannelKey of channelInsert.templateChannels) {\n        for (const pixelKey of pixelKeys) {\n          channelKeys.push(TemplateChannel.resolveTemplateString(templateChannelKey, {\n            pixelKey,\n          }));\n        }\n      }\n    }\n\n    return channelKeys;\n  }\n\n  /**\n   * Resolves `repeatFor` keywords into a list of pixel (group) keys or just returns the given pixel (group) key array.\n   * @private\n   * @param {string | string[]} repeatFor A matrix channel insert's repeatFor property.\n   * @returns {string[]} The properly ordered list of pixel (group) keys.\n   */\n  _getRepeatForPixelKeys(repeatFor) {\n    if (Array.isArray(repeatFor)) {\n      // custom pixel key list\n      return repeatFor;\n    }\n\n    const matrix = this.fixture.matrix;\n\n    if (repeatFor === 'eachPixelGroup') {\n      return matrix.pixelGroupKeys;\n    }\n\n    if (repeatFor === 'eachPixelABC') {\n      return matrix.pixelKeys;\n    }\n\n    // eachPixelXYZ, eachPixelZYX, ...\n    const orderByAxes = repeatFor.replace('eachPixel', '');\n    return matrix.getPixelKeysByOrder(orderByAxes[0], orderByAxes[1], orderByAxes[2]);\n  }\n\n  /**\n   * @returns {AbstractChannel[]} The mode's channels. The count and position equals to actual DMX channel count and position.\n   */\n  get channels() {\n    let nullChannelsFound = 0;\n    const channels = this.channelKeys.map((channelKey) => {\n      if (channelKey === null) {\n        nullChannelsFound++;\n        return this.fixture.nullChannels[nullChannelsFound - 1];\n      }\n      return this.fixture.getChannelByKey(channelKey);\n    });\n\n    return cacheResult(this, 'channels', channels);\n  }\n\n  /**\n   * @param {string} channelKey The key of the channel to get the index for.\n   * @param {SwitchingChannelBehavior} [switchingChannelBehavior='all'] Controls how switching channels are counted, see {@link SwitchingChannel#usesChannelKey} for possible values.\n   * @returns {number} The index of the given channel in this mode or -1 if not found.\n   */\n  getChannelIndex(channelKey, switchingChannelBehavior = 'all') {\n    return this.channels.findIndex((channel) => {\n      if (channel === null) {\n        return false;\n      }\n\n      if (channel instanceof SwitchingChannel) {\n        return channel.usesChannelKey(channelKey, switchingChannelBehavior);\n      }\n\n      return channel.key === channelKey;\n    });\n  }\n}\n\nexport default Mode;\n"
  },
  {
    "path": "lib/model/NullChannel.js",
    "content": "import { v4 as uuidv4 } from 'uuid';\nimport CoarseChannel from './CoarseChannel.js';\n/** @import Fixture from './Fixture.js' */\n\n/**\n * Dummy channel used to represent `null` in a mode's channel list.\n * @extends CoarseChannel\n */\nclass NullChannel extends CoarseChannel {\n  /**\n   * Creates a new NullChannel instance by creating a Channel object with NoFunction channel data.\n   * Uses a unique uuid as channel key.\n   * @param {Fixture} fixture The fixture this channel is associated to.\n   */\n  constructor(fixture) {\n    super(`null-${uuidv4()}`, {\n      name: 'No Function',\n      capability: {\n        type: 'NoFunction',\n      },\n    }, fixture);\n  }\n}\n\nexport default NullChannel;\n"
  },
  {
    "path": "lib/model/Physical.js",
    "content": "/**\n * A fixture's technical data, belonging to the hardware and not the DMX protocol.\n */\nclass Physical {\n  /**\n   * Creates a new Physical instance.\n   * @param {object} jsonObject A fixture's or mode's physical JSON data.\n   */\n  constructor(jsonObject) {\n    this._jsonObject = jsonObject;\n  }\n\n  /**\n   * @returns {object} The object from the JSON data that is represented by this Physical object.\n   */\n  get jsonObject() {\n    return this._jsonObject;\n  }\n\n  /**\n   * @returns {number[] | null} Width, height and depth of the fixture in millimeters. Defaults to null.\n   */\n  get dimensions() {\n    return this._jsonObject.dimensions || null;\n  }\n\n  /**\n   * @returns {number | null} Width of the fixture in millimeters. Defaults to null.\n   */\n  get width() {\n    return this.dimensions === null ? null : this.dimensions[0];\n  }\n\n  /**\n   * @returns {number | null} Height of the fixture in millimeters. Defaults to null.\n   */\n  get height() {\n    return this.dimensions === null ? null : this.dimensions[1];\n  }\n\n  /**\n   * @returns {number | null} Depth of the fixture in millimeters. Defaults to null.\n   */\n  get depth() {\n    return this.dimensions === null ? null : this.dimensions[2];\n  }\n\n  /**\n   * @returns {number | null} Weight of the fixture in kilograms. Defaults to null.\n   */\n  get weight() {\n    return this._jsonObject.weight || null;\n  }\n\n  /**\n   * @returns {number | null} Power consumption of the fixture in watts. Defaults to null.\n   */\n  get power() {\n    return this._jsonObject.power || null;\n  }\n\n  /**\n   * @returns {Record<string, string>} Power connector information.\n   */\n  get powerConnectors() {\n    return this._jsonObject.powerConnectors || {};\n  }\n\n  /**\n   * @returns {string | null} The DMX plug to be used to control the fixture, e.g. \"3-pin\" (XLR). Defaults to null.\n   */\n  get DMXconnector() {\n    return this._jsonObject.DMXconnector || null;\n  }\n\n  /**\n   * @returns {boolean} Whether physical data about the light source is available.\n   */\n  get hasBulb() {\n    return 'bulb' in this._jsonObject;\n  }\n\n  /**\n   * @returns {string | null} The kind of lamp that is used in the fixture, e.g. \"LED\". Defaults to null.\n   */\n  get bulbType() {\n    return this.hasBulb ? (this._jsonObject.bulb.type || null) : null;\n  }\n\n  /**\n   * @returns {number | null} The color temperature of the bulb in kelvins. Defaults to null.\n   */\n  get bulbColorTemperature() {\n    return this.hasBulb ? (this._jsonObject.bulb.colorTemperature || null) : null;\n  }\n\n  /**\n   * @returns {number | null} The luminous flux of the bulb in lumens. Defaults to null.\n   */\n  get bulbLumens() {\n    return this.hasBulb ? (this._jsonObject.bulb.lumens || null) : null;\n  }\n\n  /**\n   * @returns {boolean} Whether physical data about the lens is available.\n   */\n  get hasLens() {\n    return 'lens' in this._jsonObject;\n  }\n\n  /**\n   * @returns {string | null} The kind of lens that is used in the fixture, e.g. \"Fresnel\". Defaults to null.\n   */\n  get lensName() {\n    return this.hasLens ? (this._jsonObject.lens.name || null) : null;\n  }\n\n  /**\n   * @returns {number | null} The minimum possible beam angle in degrees. Defaults to null.\n   */\n  get lensDegreesMin() {\n    return this.hasLens && 'degreesMinMax' in this._jsonObject.lens ? this._jsonObject.lens.degreesMinMax[0] : null;\n  }\n\n  /**\n   * @returns {number | null} The maximum possible beam angle in degrees. Defaults to null.\n   */\n  get lensDegreesMax() {\n    return this.hasLens && 'degreesMinMax' in this._jsonObject.lens ? this._jsonObject.lens.degreesMinMax[1] : null;\n  }\n\n  /**\n   * @returns {boolean} Whether physical data about the matrix is available.\n   */\n  get hasMatrixPixels() {\n    return 'matrixPixels' in this._jsonObject;\n  }\n\n  /**\n   * @returns {number[] | null} Width, height, depth of a matrix pixel in millimeters.\n   */\n  get matrixPixelsDimensions() {\n    return this.hasMatrixPixels ? this._jsonObject.matrixPixels.dimensions : null;\n  }\n\n  /**\n   * @returns {number[] | null} XYZ-Spacing between matrix pixels in millimeters.\n   */\n  get matrixPixelsSpacing() {\n    return this.hasMatrixPixels ? this._jsonObject.matrixPixels.spacing : null;\n  }\n}\n\nexport default Physical;\n"
  },
  {
    "path": "lib/model/Range.js",
    "content": "/**\n * Represents a range from one integer to a higher or equal integer. Primarily used for DMX ranges of capabilities.\n */\nclass Range {\n  /**\n   * Creates a new Range instance.\n   * @param {number[]} rangeArray Array of start and end value. Start value may not be greater than end value.\n   */\n  constructor(rangeArray) {\n    this._rangeArray = rangeArray;\n  }\n\n  /**\n   * @returns {number} The start number of the range. Lower or equal to end.\n   */\n  get start() {\n    return this._rangeArray[0];\n  }\n\n  /**\n   * @returns {number} The end number of the range. Higher or equal to start.\n   */\n  get end() {\n    return this._rangeArray[1];\n  }\n\n  /**\n   * @returns {number} The arithmetic mean of start and end value. Can be a fraction.\n   */\n  get center() {\n    return Math.floor((this.start + this.end) / 2);\n  }\n\n  /**\n   * @param {number} value The number to check whether it's in the range.\n   * @returns {boolean} Whether the given number is inside this range, i.e. if it's not lower than the start value and not higher than the end value.\n   */\n  contains(value) {\n    return this.start <= value && value <= this.end;\n  }\n\n  /**\n   * @param {Range} range Another Range object.\n   * @returns {boolean} Whether this range overlaps with the given one.\n   */\n  overlapsWith(range) {\n    return range.end > this.start && range.start < this.end;\n  }\n\n  /**\n   * @param {Range[]} ranges An array of Range objects.\n   * @returns {boolean} Whether this range overlaps with any of the given ones.\n   */\n  overlapsWithOneOf(ranges) {\n    return ranges.some((range) => this.overlapsWith(range));\n  }\n\n  /**\n   * @param {Range} range Another Range object.\n   * @returns {boolean} Whether this range is exactly next to the given one, i.e. the lower range's end value is by 1 lower than the higher range's start value.\n   */\n  isAdjacentTo(range) {\n    return range.end + 1 === this.start || this.end + 1 === range.start;\n  }\n\n  /**\n   * @param {Range} range Another range to merge with.\n   * @returns {Range} A new range that covers both the initial and the other range.\n   */\n  getRangeMergedWith(range) {\n    return new Range([Math.min(this.start, range.start), Math.max(this.end, range.end)]);\n  }\n\n  /**\n   * @returns {string} Textual representation of this range.\n   */\n  toString() {\n    return this.start === this.end ? this.start.toString() : `${this.start}…${this.end}`;\n  }\n\n  /**\n   * Merge specified Range objects. Asserts that ranges don't overlap and that all ranges are valid (start<=end).\n   * @param {Range[]} ranges Range objects to merge into as few ranges as possible.\n   * @returns {Range[]} Merged ranges.\n   */\n  static getMergedRanges(ranges) {\n    // copy ranges\n    const mergedRanges = ranges.map((range) => new Range([range.start, range.end]));\n\n    // try to merge ranges one by one\n    for (let index = 0; index < mergedRanges.length; index++) {\n      const range = mergedRanges[index];\n      const mergableRangeIndex = mergedRanges.findIndex((otherRange) => otherRange.isAdjacentTo(range));\n\n      if (mergableRangeIndex !== -1) {\n        // replace current range with merged range and delete other range\n        mergedRanges[index] = mergedRanges[mergableRangeIndex].getRangeMergedWith(range);\n        mergedRanges.splice(mergableRangeIndex, 1);\n\n        // indices have been shifted, so the current index needs to be iterated another time\n        index--;\n      }\n    }\n\n    return mergedRanges;\n  }\n}\n\nexport default Range;\n"
  },
  {
    "path": "lib/model/Resource.js",
    "content": "import cacheResult from '../cache-result.js';\n\n/**\n * Information about a resource.\n */\nclass Resource {\n  /**\n   * Creates a new Resource instance.\n   * @param {object} jsonObject An embedded resource object from the fixture's JSON data.\n   */\n  constructor(jsonObject) {\n    this._jsonObject = jsonObject;\n  }\n\n  // part of the resource JSON:\n\n  /**\n   * @returns {string} The resource's name.\n   */\n  get name() {\n    return this._jsonObject.name;\n  }\n\n  /**\n   * @returns {string[]} An array of keywords belonging to this resource.\n   */\n  get keywords() {\n    return (this._jsonObject.keywords || '').split(' ');\n  }\n\n  /**\n   * @returns {string | null} The source this resource was taken from, or null if it's not specified.\n   */\n  get source() {\n    return this._jsonObject.source || null;\n  }\n\n  // added by embedding into the fixture:\n\n  /**\n   * @returns {string} The resource key.\n   */\n  get key() {\n    return this._jsonObject.key;\n  }\n\n  /**\n   * @returns {string} The resource name, i.e. its directory.\n   */\n  get type() {\n    return this._jsonObject.type;\n  }\n\n  /**\n   * @returns {string | null} The resource alias, as specified in the fixture, or null if the resource was referenced directly.\n   */\n  get alias() {\n    return this._jsonObject.alias || null;\n  }\n\n  /**\n   * @returns {boolean} True if this resource has an associated image, false otherwise.\n   */\n  get hasImage() {\n    return 'image' in this._jsonObject;\n  }\n\n  /**\n   * @returns {string | null} The resource image's file extension, or null if there is no image.\n   */\n  get imageExtension() {\n    return this.hasImage ? this._jsonObject.image.extension : null;\n  }\n\n  /**\n   * @returns {string | null} The resource image's MIME type, or null if there is no image.\n   */\n  get imageMimeType() {\n    return this.hasImage ? this._jsonObject.image.mimeType : null;\n  }\n\n  /**\n   * @returns {string | null} The resource image data (base64 or utf-8 encoded), or null if there is no image.\n   */\n  get imageData() {\n    return this.hasImage ? this._jsonObject.image.data : null;\n  }\n\n  /**\n   * @returns {'base64' | 'utf-8' | null} The resource image's data encoding, or null if there is no image.\n   */\n  get imageEncoding() {\n    return this.hasImage ? this._jsonObject.image.encoding : null;\n  }\n\n  /**\n   * @returns {string | null} A data URL containing the resource image, or null if there is no image.\n   */\n  get imageDataUrl() {\n    if (!this.hasImage) {\n      return cacheResult(this, 'imageDataUrl', null);\n    }\n\n    let mimeType = this.imageMimeType;\n\n    const imageData = encodeURIComponent(this.imageData)\n      .replaceAll('(', '%28') // Encode brackets\n      .replaceAll(')', '%29');\n\n    if (this.imageEncoding === 'base64') {\n      mimeType += ';base64';\n    }\n\n    return cacheResult(this, 'imageDataUrl', `data:${mimeType},${imageData}`);\n  }\n}\n\nexport default Resource;\n"
  },
  {
    "path": "lib/model/SwitchingChannel.js",
    "content": "import cacheResult from '../cache-result.js';\nimport AbstractChannel from './AbstractChannel.js';\nimport Range from './Range.js';\n/** @import Fixture from './Fixture.js' */\n\n/**\n * Represents a channel that switches its behavior depending on trigger channel's value.\n * The different behaviors are implemented as different {@link CoarseChannel}s or {@link FineChannel}s.\n * @extends AbstractChannel\n */\nclass SwitchingChannel extends AbstractChannel {\n  /**\n   * Creates a new SwitchingChannel instance.\n   * @param {string} alias The unique switching channel alias as defined in the trigger channel's `switchChannels` properties.\n   * @param {AbstractChannel} triggerChannel The channel whose DMX value this channel depends on.\n   */\n  constructor(alias, triggerChannel) {\n    super(alias);\n    this._triggerChannel = triggerChannel;\n  }\n\n  /**\n   * @returns {AbstractChannel} The channel whose DMX value this switching channel depends on.\n   */\n  get triggerChannel() {\n    return this._triggerChannel;\n  }\n\n  /**\n   * Overrides [`AbstractChannel.fixture`]{@link AbstractChannel#fixture}.\n   * @returns {Fixture} The fixture in which this channel is used.\n   */\n  get fixture() {\n    return this.triggerChannel.fixture;\n  }\n\n  /**\n   * @typedef {object} TriggerCapability\n   * @property {Range} dmxRange The DMX range that triggers the switching channel.\n   * @property {string} switchTo The channel to switch to in the given DMX range.\n   */\n\n  /**\n   * @returns {TriggerCapability[]} The trigger channel's capabilities in a compact form to only include the DMX range and which channel should be switched to. DMX values are given in the trigger channel's highest possible resolution.\n   */\n  get triggerCapabilities() {\n    return cacheResult(this, 'triggerCapabilities', this.triggerChannel.capabilities.map(\n      (capability) => ({\n        dmxRange: capability.dmxRange,\n        switchTo: capability.switchChannels[this.key],\n      }),\n    ));\n  }\n\n  /**\n   * @returns {Record<string, Range[]>} Keys of channels that can be switched to pointing to an array of DMX values the trigger channel must be set to to active the channel. DMX values are given in the trigger channel's highest possible resolution.\n   */\n  get triggerRanges() {\n    const triggerRanges = {};\n\n    // group ranges by switchTo\n    for (const capability of this.triggerCapabilities) {\n      if (!(capability.switchTo in triggerRanges)) {\n        triggerRanges[capability.switchTo] = [];\n      }\n      triggerRanges[capability.switchTo].push(capability.dmxRange);\n    }\n\n    // merge each group of ranges\n    for (const channel of Object.keys(triggerRanges)) {\n      triggerRanges[channel] = Range.getMergedRanges(triggerRanges[channel]);\n    }\n\n    return cacheResult(this, 'triggerRanges', triggerRanges);\n  }\n\n  /**\n   * @returns {string} The key of the channel that is activated when the trigger channel is set to its default value.\n   */\n  get defaultChannelKey() {\n    return cacheResult(this, 'defaultChannelKey', this.triggerCapabilities.find(\n      (capability) => capability.dmxRange.contains(this.triggerChannel.defaultValue),\n    ).switchTo);\n  }\n\n  /**\n   * @returns {AbstractChannel} The channel that is activated when the trigger channel is set to its default value.\n   */\n  get defaultChannel() {\n    return cacheResult(this, 'defaultChannel', this.fixture.getChannelByKey(this.defaultChannelKey));\n  }\n\n  /**\n   * @returns {string[]} All channel keys this channel can be switched to.\n   */\n  get switchToChannelKeys() {\n    const switchToChannelKeys = this.triggerCapabilities\n      .map((capability) => capability.switchTo)\n      .filter((channelKey, index, array) => array.indexOf(channelKey) === index); // filter duplicates\n\n    return cacheResult(this, 'switchToChannelKeys', switchToChannelKeys);\n  }\n\n  /**\n   * @returns {AbstractChannel[]} All channels this channel can be switched to.\n   */\n  get switchToChannels() {\n    return cacheResult(this, 'switchToChannels', this.switchToChannelKeys.map(\n      (channelKey) => this.fixture.getChannelByKey(channelKey),\n    ));\n  }\n\n  /**\n   * @typedef {'keyOnly' | 'defaultOnly' | 'switchedOnly' | 'all'} SwitchingChannelBehavior\n   */\n\n  /**\n   * @param {string} channelKey The channel key to search for.\n   * @param {SwitchingChannelBehavior} [switchingChannelBehavior='all'] Define which channels to include in the search.\n   * @returns {boolean} Whether this SwitchingChannel contains the given channel key.\n   */\n  usesChannelKey(channelKey, switchingChannelBehavior = 'all') {\n    if (switchingChannelBehavior === 'keyOnly') {\n      return this.key === channelKey;\n    }\n\n    if (switchingChannelBehavior === 'defaultOnly') {\n      return this.defaultChannel.key === channelKey;\n    }\n\n    if (switchingChannelBehavior === 'switchedOnly') {\n      return this.switchToChannelKeys.includes(channelKey);\n    }\n\n    return this.switchToChannelKeys.includes(channelKey) || this.key === channelKey;\n  }\n\n  /**\n   * @returns {boolean} True if help is needed in one of the switched channels, false otherwise.\n   */\n  get isHelpWanted() {\n    return cacheResult(this, 'isHelpWanted', this.switchToChannels.some(\n      (channel) => channel.isHelpWanted,\n    ));\n  }\n}\n\nexport default SwitchingChannel;\n"
  },
  {
    "path": "lib/model/TemplateChannel.js",
    "content": "import cacheResult from '../cache-result.js';\nimport CoarseChannel from './CoarseChannel.js';\n/** @import AbstractChannel from './AbstractChannel.js' */\n/** @import Fixture from './Fixture.js' */\n\n/**\n * Represents a blueprint channel of which several similar channels can be generated.\n * Currently used to create matrix channels.\n */\nclass TemplateChannel extends CoarseChannel {\n  /**\n   * Creates new TemplateChannel instance. Also clears cache by setting jsonObject.\n   * @param {string} key The templateChannel's key with the required variables.\n   * @param {object} jsonObject The template's JSON data which looks pretty similar to a normal channel's data except that channel aliases must include variables.\n   * @param {Fixture} fixture The Fixture instance.\n   */\n  constructor(key, jsonObject, fixture) {\n    super(key, jsonObject, fixture);\n  }\n\n  /**\n   * @returns {string[]} Template keys and aliases introduced by this channel, i.e. the channel key itself and defined fine and switching channels.\n   */\n  get allTemplateKeys() {\n    return cacheResult(this, 'allTemplateKeys', [this.key, ...this.fineChannelAliases, ...this.switchingChannelAliases]);\n  }\n\n  /**\n   * @returns {Map<string, string[]>} All template keys pointing to the key resolved with each pixel key to a matrix channel key.\n   */\n  get possibleMatrixChannelKeys() {\n    const possibleMatrixChannelKeys = new Map();\n\n    for (const templateKey of this.allTemplateKeys) {\n      const pixelKeys = [...this.fixture.matrix.pixelKeys, ...this.fixture.matrix.pixelGroupKeys];\n      possibleMatrixChannelKeys.set(templateKey, pixelKeys.map(\n        (pixelKey) => TemplateChannel.resolveTemplateString(templateKey, { pixelKey }),\n      ));\n    }\n\n    return cacheResult(this, 'possibleMatrixChannelKeys', possibleMatrixChannelKeys);\n  }\n\n  /**\n   * Creates matrix channels from this template channel (together with its fine and switching channels if defined) and all pixel keys.\n   * @returns {AbstractChannel[]} The generated channels associated to the given pixel key and its fine and switching channels.\n   */\n  createMatrixChannels() {\n    const matrixChannels = [];\n\n    const pixelKeys = [...this.fixture.matrix.pixelKeys, ...this.fixture.matrix.pixelGroupKeys];\n    for (const pixelKey of pixelKeys) {\n      const templateVariables = { pixelKey };\n\n      // create a new CoarseChannel from the resolved channel data\n      const jsonData = TemplateChannel.resolveTemplateObject(this._jsonObject, templateVariables);\n      const channelKey = TemplateChannel.resolveTemplateString(this._key, templateVariables);\n      const mainChannel = new CoarseChannel(channelKey, jsonData, this.fixture);\n\n      const channels = [mainChannel, ...mainChannel.fineChannels, ...mainChannel.switchingChannels];\n      for (const channel of channels) {\n        channel.pixelKey = pixelKey;\n      }\n      matrixChannels.push(...channels);\n    }\n\n    return matrixChannels;\n  }\n\n  /**\n   * Replaces the specified variables in the specified object by cloning the object.\n   * @param {object} object The object which has to be modified.\n   * @param {Record<string, string>} variables Each variable (without $) pointing to its value.\n   * @returns {object} A copy of the object with replaced variables.\n   */\n  static resolveTemplateObject(object, variables) {\n    return JSON.parse(TemplateChannel.resolveTemplateString(JSON.stringify(object), variables));\n  }\n\n  /**\n   * Replaces the specified variables in the specified string.\n   * @param {string} string The string which has to be modified.\n   * @param {Record<string, string>} variables Each variable (without $) pointing to its value.\n   * @returns {string} The modified string.\n   */\n  static resolveTemplateString(string, variables) {\n    for (const variable of (Object.keys(variables))) {\n      string = stringReplaceAll(string, `$${variable}`, variables[variable]);\n    }\n    return string;\n  }\n}\n\nexport default TemplateChannel;\n\n/**\n * @ignore\n * @param {string} string The string to operate on.\n * @param {string} search A string that is to be replaced by replacement. It is treated as a verbatim string and is not interpreted as a regular expression.\n * @param {string} replacement The string that replaces the substring specified by the specified search parameter.\n * @returns {string} The string with all matches of the search pattern replaced by the replacement.\n */\nfunction stringReplaceAll(string, search, replacement) {\n  return string.split(search).join(replacement);\n}\n"
  },
  {
    "path": "lib/model/Wheel.js",
    "content": "import cacheResult from '../cache-result.js';\nimport WheelSlot from './WheelSlot.js';\n\n/**\n * Information about a fixture's wheel.\n */\nclass Wheel {\n  /**\n   * Creates a new Wheel instance.\n   * @param {string} wheelName The wheel's name, like specified in the JSON.\n   * @param {object} jsonObject A wheel object from the fixture's JSON data.\n   */\n  constructor(wheelName, jsonObject) {\n    this._name = wheelName;\n    this._jsonObject = jsonObject;\n    this._splitSlots = {};\n    this._slotsOfType = {};\n  }\n\n  /**\n   * @returns {string} The wheel's name.\n   */\n  get name() {\n    return this._name;\n  }\n\n  /**\n   * @returns {'CW' | 'CCW'} The direction the wheel's slots are arranged in. Defaults to clockwise.\n   */\n  get direction() {\n    return this._jsonObject.direction || 'CW';\n  }\n\n  /**\n   * @returns {string} The type of the Wheel, i.e. the most frequent slot type (except for animation gobo wheels; the wheel type is AnimationGobo there).\n   */\n  get type() {\n    // see https://stackoverflow.com/a/20762713/451391\n\n    const slotTypes = this.slots.map((slot) => slot.type);\n\n    // sort by number of occurrences\n    slotTypes.sort((a, b) => {\n      const occurrencesOfA = slotTypes.filter((type) => type === a);\n      const occurrencesOfB = slotTypes.filter((type) => type === b);\n      return occurrencesOfA.length - occurrencesOfB.length;\n    });\n\n    const type = slotTypes.pop();\n\n    if (type.startsWith('AnimationGobo')) {\n      return 'AnimationGobo';\n    }\n\n    return type;\n  }\n\n  /**\n   * @returns {WheelSlot[]} Array of wheel slots.\n   */\n  get slots() {\n    return cacheResult(this, 'slots', this._jsonObject.slots.map(\n      (slotJson) => new WheelSlot(slotJson, this),\n    ));\n  }\n\n  /**\n   * @param {number} slotNumber The one-based slot number.\n   * @returns {WheelSlot} The slot object. Can be a split slot object, if a non-integer index is specified.\n   */\n  getSlot(slotNumber) {\n    if (slotNumber % 1 === 0) {\n      return this.slots[this.getAbsoluteSlotIndex(slotNumber)];\n    }\n\n    const floorIndex = this.getAbsoluteSlotIndex(Math.floor(slotNumber));\n    const ceilIndex = this.getAbsoluteSlotIndex(Math.ceil(slotNumber));\n    const splitKey = `Split ${floorIndex}/${ceilIndex}`;\n\n    if (!(splitKey in this._splitSlots)) {\n      // split slot\n      const floorSlot = this.slots[floorIndex];\n      const ceilSlot = this.slots[ceilIndex];\n\n      this._splitSlots[splitKey] = new WheelSlot(null, this, floorSlot, ceilSlot);\n    }\n\n    return this._splitSlots[splitKey];\n  }\n\n  /**\n   * @param {number} slotNumber The one-based slot number, can be smaller than 1 and greater than the number of slots.\n   * @returns {number} The zero-based slot index, bounded by the number of slots.\n   */\n  getAbsoluteSlotIndex(slotNumber) {\n    return ((slotNumber - 1) % this.slots.length) + (slotNumber < 1 ? this.slots.length : 0);\n  }\n\n  /**\n   * @param {string} type The wheel slot type to search for.\n   * @returns {WheelSlot[]} All slots with the given type.\n   */\n  getSlotsOfType(type) {\n    if (!(type in this._slotsOfType)) {\n      this._slotsOfType[type] = this.slots.filter(\n        (slot) => slot.type === type,\n      );\n    }\n\n    return this._slotsOfType[type];\n  }\n}\n\nexport default Wheel;\n"
  },
  {
    "path": "lib/model/WheelSlot.js",
    "content": "import cacheResult from '../cache-result.js';\nimport Entity from './Entity.js';\nimport Resource from './Resource.js';\n/** @import Wheel from './Wheel.js' */\n\n/** @ignore */\nconst namePerType = {\n  Color: (slot, name) => {\n    if (name !== null && slot.colorTemperature !== null) {\n      return `${name} (${slot.colorTemperature.toString()})`;\n    }\n\n    if (slot.colorTemperature !== null) {\n      return slot.colorTemperature.toString();\n    }\n\n    return name;\n  },\n  Gobo: (slot, name) => {\n    if (name === null) {\n      if (slot.resource !== null) {\n        return `Gobo ${slot.resource.name}`;\n      }\n\n      return null;\n    }\n\n    if (name.startsWith('Gobo')) {\n      return name;\n    }\n\n    return `Gobo ${name}`;\n  },\n  Prism: (slot, name) => {\n    if (name !== null && slot.facets !== null) {\n      return `${slot.facets}-facet ${name}`;\n    }\n\n    if (slot.facets !== null) {\n      return `${slot.facets}-facet prism`;\n    }\n\n    return name;\n  },\n  Iris: (slot, name) => {\n    if (slot.openPercent !== null) {\n      return `Iris ${slot.openPercent.toString()}`;\n    }\n\n    return null;\n  },\n  Frost: (slot, name) => {\n    if (slot.frostIntensity !== null) {\n      return `Frost ${slot.frostIntensity.toString()}`;\n    }\n\n    return null;\n  },\n  Split: (slot, name) => {\n    return `Split ${slot.floorSlot.name} / ${slot.ceilSlot.name}`;\n  },\n  AnimationGoboStart: (slot, name) => {\n    return name === null ? null : `${name} Start`;\n  },\n  AnimationGoboEnd: (slot, name) => {\n    const slotNumber = slot._wheel.slots.indexOf(slot) + 1;\n    const previousSlot = slot._wheel.getSlot(slotNumber - 1);\n\n    return previousSlot._jsonObject.name ? `${previousSlot._jsonObject.name} End` : null;\n  },\n  AnimationGobo: (slot, name) => {\n    return slot.floorSlot.name.replace(' Start', '');\n  },\n  Default: (slot, name) => {\n    return name;\n  },\n};\n\n/**\n * Information about a single wheel slot (or a split slot).\n */\nclass WheelSlot {\n  /**\n   * Creates a new WheelSlot instance.\n   * @param {object | null} jsonObject A wheel slot object from the fixture's JSON data. If null, this WheelSlot is a split slot.\n   * @param {Wheel} wheel The wheel that this slot belongs to.\n   * @param {WheelSlot | null} floorSlot For split slots, the WheelSlot instance at the start.\n   * @param {WheelSlot | null} ceilSlot For split slots, the WheelSlot instance at the end.\n   */\n  constructor(jsonObject, wheel, floorSlot = null, ceilSlot = null) {\n    this._jsonObject = jsonObject;\n    this._wheel = wheel;\n    this._floorSlot = floorSlot;\n    this._ceilSlot = ceilSlot;\n  }\n\n  /**\n   * @returns {boolean} True if this WheelSlot instance represents a split slot.\n   */\n  get isSplitSlot() {\n    return this._jsonObject === null;\n  }\n\n  /**\n   * @returns {string} The slot's type.\n   */\n  get type() {\n    if (!this.isSplitSlot) {\n      return cacheResult(this, 'type', this._jsonObject.type);\n    }\n\n    if (this._floorSlot.type === 'AnimationGoboStart') {\n      return cacheResult(this, 'type', 'AnimationGobo');\n    }\n\n    return cacheResult(this, 'type', 'Split');\n  }\n\n  /**\n   * @returns {number} The zero-based index of this slot amongst all slots with the same type in this wheel.\n   */\n  get nthOfType() {\n    return cacheResult(this, 'nthOfType', this._wheel.getSlotsOfType(this.type).indexOf(this));\n  }\n\n  /**\n   * @returns {Resource | string | null} The gobo resource object if it was previously embedded, or the gobo resource reference string, or null if no resource is specified for the slot.\n   */\n  get resource() {\n    if (this.isSplitSlot || !('resource' in this._jsonObject)) {\n      return cacheResult(this, 'resource', null);\n    }\n\n    if (typeof this._jsonObject.resource === 'string') {\n      return cacheResult(this, 'resource', this._jsonObject.resource);\n    }\n\n    return cacheResult(this, 'resource', new Resource(this._jsonObject.resource));\n  }\n\n  /**\n   * @returns {string} The wheel slot's name.\n   */\n  get name() {\n    const nameFunction = this.type in namePerType ? namePerType[this.type] : namePerType.Default;\n    let name = nameFunction(this, this.isSplitSlot ? null : (this._jsonObject.name || null));\n\n    if (name === null) {\n      const typeName = this.type.replaceAll(/([a-z])([A-Z])/g, '$1 $2'); // 'CamelCase' -> 'Camel Case'\n      name = this._wheel.getSlotsOfType(this.type).length === 1 ? typeName : `${typeName} ${this.nthOfType + 1}`;\n    }\n\n    return cacheResult(this, 'name', name);\n  }\n\n  /**\n   * @returns {string[] | null} The colors of this wheel slot, or null if this slot has no colors.\n   */\n  get colors() {\n    const fixedColors = {\n      Open: ['#ffffff'],\n      Closed: ['#000000'],\n    };\n\n    if (this.type in fixedColors) {\n      return cacheResult(this, 'colors', fixedColors[this.type]);\n    }\n\n    if (this.isSplitSlot) {\n      if (this._floorSlot.colors && this._ceilSlot.colors) {\n        return cacheResult(this, 'colors', [...this._floorSlot.colors, ...this._ceilSlot.colors]);\n      }\n    }\n    else if ('colors' in this._jsonObject) {\n      return cacheResult(this, 'colors', this._jsonObject.colors);\n    }\n\n    return cacheResult(this, 'colors', null);\n  }\n\n  /**\n   * @returns {Entity | null} For Color slots, the slot's color temperature. Null if this slot has no color temperature.\n   */\n  get colorTemperature() {\n    if ('colorTemperature' in this._jsonObject) {\n      return cacheResult(this, 'colorTemperature', Entity.createFromEntityString(this._jsonObject.colorTemperature));\n    }\n\n    return cacheResult(this, 'colorTemperature', null);\n  }\n\n  /**\n   * @returns {number | null} For Prism slots, the number of prism facets. Null if number of facets is not defined.\n   */\n  get facets() {\n    return this._jsonObject.facets || null;\n  }\n\n  /**\n   * @returns {Entity | null} For Iris slots, the slot's openPercent value. Null if this slot has no openPercent value.\n   */\n  get openPercent() {\n    if ('openPercent' in this._jsonObject) {\n      return cacheResult(this, 'openPercent', Entity.createFromEntityString(this._jsonObject.openPercent));\n    }\n\n    return cacheResult(this, 'openPercent', null);\n  }\n\n  /**\n   * @returns {Entity | null} For Frost slots, the slot's frost intensity. Null if this slot has no frost intensity.\n   */\n  get frostIntensity() {\n    if ('frostIntensity' in this._jsonObject) {\n      return cacheResult(this, 'frostIntensity', Entity.createFromEntityString(this._jsonObject.frostIntensity));\n    }\n\n    return cacheResult(this, 'frostIntensity', null);\n  }\n\n  /**\n   * @returns {WheelSlot | null} For split slots, the floor (start) slot. Null for non-split slots.\n   */\n  get floorSlot() {\n    return this._floorSlot || null;\n  }\n\n  /**\n   * @returns {WheelSlot | null} For split slots, the ceil (end) slot. Null for non-split slots.\n   */\n  get ceilSlot() {\n    return this._ceilSlot || null;\n  }\n}\n\nexport default WheelSlot;\n"
  },
  {
    "path": "lib/model.js",
    "content": "import { readFile } from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport importJson from './import-json.js';\nimport Fixture from './model/Fixture.js';\nimport Manufacturer from './model/Manufacturer.js';\n\n/**\n * Look up the fixture definition in the directory structure and create a Fixture instance.\n * @param {string} absolutePath The fixture file absolute path, including filename.\n * @returns {Promise<Fixture, Error>} A Promise that resolves to the created Fixture instance or is rejected with a `MODULE_NOT_FOUND` error if the given fixture file does not exist.\n */\nexport async function fixtureFromFile(absolutePath) {\n  let manufacturerKey = path.basename(path.dirname(absolutePath));\n  let fixtureKey = path.basename(absolutePath, path.extname(absolutePath));\n  let fixtureJson = await importJson(absolutePath);\n\n  if (fixtureJson.$schema.endsWith('/fixture-redirect.json')) {\n    [manufacturerKey, fixtureKey] = fixtureJson.redirectTo.split('/');\n    absolutePath = path.join(path.dirname(absolutePath), `../${manufacturerKey}/${fixtureKey}.json`);\n    fixtureJson = await importJson(absolutePath);\n  }\n\n  const manufacturer = await manufacturerFromRepository(manufacturerKey);\n  await embedResourcesIntoFixtureJson(fixtureJson);\n\n  return new Fixture(manufacturer, fixtureKey, fixtureJson);\n}\n\n/**\n * Look up the fixture definition in the directory structure and create a Fixture instance.\n * @param {string} manufacturerKey The manufacturer's key (directory name)\n * @param {string} fixtureKey The fixture's key (filename without .json)\n * @returns {Promise<Fixture, Error>} A Promise that resolves to the created Fixture instance or is rejected with a `MODULE_NOT_FOUND` error if the given fixture file does not exist.\n */\nexport async function fixtureFromRepository(manufacturerKey, fixtureKey) {\n  let fixturePath = `../fixtures/${manufacturerKey}/${fixtureKey}.json`;\n  let fixtureJson = await importJson(fixturePath, import.meta.url);\n\n  if (fixtureJson.$schema.endsWith('/fixture-redirect.json')) {\n    fixturePath = `../fixtures/${fixtureJson.redirectTo}.json`;\n    fixtureJson = {\n      ...await importJson(fixturePath, import.meta.url),\n      name: fixtureJson.name,\n    };\n  }\n\n  const manufacturer = await manufacturerFromRepository(manufacturerKey);\n  await embedResourcesIntoFixtureJson(fixtureJson);\n\n  return new Fixture(manufacturer, fixtureKey, fixtureJson);\n}\n\n/**\n * Look up the manufacturer definition in the directory structure and create a Manufacturer instance.\n * @param {string} manufacturerKey The manufacturer's key (directory name).\n * @returns {Promise<Manufacturer>} A Promise that resolves to the created Manufacturer instance.\n */\nexport async function manufacturerFromRepository(manufacturerKey) {\n  const manufacturers = await importJson('../fixtures/manufacturers.json', import.meta.url);\n  return new Manufacturer(manufacturerKey, manufacturers[manufacturerKey]);\n}\n\n/**\n * @param {object} fixtureJson The fixture JSON to embed resoures into.\n */\nexport async function embedResourcesIntoFixtureJson(fixtureJson) {\n  if ('wheels' in fixtureJson) {\n    for (const wheel of Object.values(fixtureJson.wheels)) {\n      for (const slot of wheel.slots) {\n        if (typeof slot.resource === 'string') {\n          slot.resource = await getResourceFromString(slot.resource);\n        }\n      }\n    }\n  }\n}\n\n/**\n * @param {string} resourceName The resource name, as specified in a fixture.\n * @returns {Promise<object>} A Promise that resolves to the resource object to be embedded into the fixture.\n */\nexport async function getResourceFromString(resourceName) {\n  const { type, key, alias } = await resolveResourceName(resourceName);\n\n  const resourceBaseUrl = new URL(`../resources/${type}/`, import.meta.url);\n  const resourceUrl = new URL(`${key}.json`, resourceBaseUrl);\n\n  let resourceData;\n\n  try {\n    resourceData = await importJson(resourceUrl);\n  }\n  catch (error) {\n    throw error instanceof SyntaxError\n      ? new Error(`Resource file '${fileURLToPath(resourceUrl)}' could not be parsed as JSON.`)\n      : new Error(`Resource '${resourceName}' not found.`);\n  }\n\n  resourceData.key = key;\n  resourceData.type = type;\n  resourceData.alias = alias;\n  resourceData.image = await getImageForResource(type, resourceBaseUrl, key);\n\n  delete resourceData.$schema;\n\n  return resourceData;\n}\n\n/**\n * @typedef {object} ResolvedResourceName\n * @property {string} type The resource type, i.e. name of the directory inside the resources directory.\n * @property {string} key The resource key.\n * @property {string | null} alias The original resource name if it's an alias, null otherwise.\n */\n\n/**\n * @param {string} resourceName The resource name, as specified in a fixture.\n * @returns {Promise<ResolvedResourceName>} A Promise that resolves to the resolved resource name object.\n */\nasync function resolveResourceName(resourceName) {\n  const [type, ...remainingParts] = resourceName.split('/');\n\n  if (remainingParts[0] === 'aliases') {\n    const aliasFileName = remainingParts[1];\n    const aliasKey = remainingParts.slice(2).join('/');\n    const aliasesFilePath = `resources/${type}/aliases/${aliasFileName}.json`;\n\n    let aliases;\n    try {\n      aliases = await importJson(`../${aliasesFilePath}`, import.meta.url);\n    }\n    catch {\n      throw new Error(`Resource aliases file '${aliasesFilePath}' not found.`);\n    }\n\n    if (!(aliasKey in aliases)) {\n      throw new Error(`Resource alias '${aliasKey}' not defined in file '${aliasesFilePath}'.`);\n    }\n\n    return {\n      type,\n      key: aliases[aliasKey],\n      alias: `${aliasFileName}/${aliasKey}`,\n    };\n  }\n\n  return {\n    type,\n    key: remainingParts.join('/'),\n    alias: null,\n  };\n}\n\n/**\n * @typedef {object} ResourceImage\n * @property {string} dataUrl The data URL of the image.\n * @property {string} extension The extension of the image file.\n */\n\nconst resourceFileFormats = [\n  {\n    extension: 'svg',\n    mimeType: 'image/svg+xml;charset=utf-8',\n    encoding: 'utf-8',\n  },\n  {\n    extension: 'png',\n    mimeType: 'image/png',\n    encoding: 'base64',\n  },\n];\n\n/**\n * @param {string} type The resource type, i.e. name of the directory inside the resources directory.\n * @param {URL} baseUrl The path of the resource directory.\n * @param {string} key The resource key.\n * @returns {Promise<ResourceImage | undefined>} A Promise that resolves to the resource image, or undefined if none could be found.\n */\nasync function getImageForResource(type, baseUrl, key) {\n  for (const { extension, mimeType, encoding } of resourceFileFormats) {\n    try {\n      let data = await readFile(new URL(`${key}.${extension}`, baseUrl), encoding);\n\n      if (extension === 'svg') {\n        // see https://cloudfour.com/thinks/simple-svg-placeholder/#how-it-works\n\n        data = data\n          .replaceAll(/[\\t\\n\\r]/gim, '') // Strip newlines and tabs\n          .replaceAll(/\\s\\s+/g, ' ') // Condense multiple spaces\n          .replaceAll(/'/gim, String.raw`\\i`) // Normalize quotes\n          .replaceAll(/<!--(.*(?=-->))-->/gim, ''); // Strip comments\n      }\n\n      return { mimeType, extension, data, encoding };\n    }\n    catch {\n      // image does not exist\n    }\n  }\n\n  if (type === 'gobos') {\n    const fileExtensions = resourceFileFormats.map(({ extension }) => extension).join(', ');\n    throw new Error(`Expected gobo image for resource '${fileURLToPath(new URL(key, baseUrl))}' not found (supported file extensions: ${fileExtensions}).`);\n  }\n\n  return undefined;\n}\n"
  },
  {
    "path": "lib/register.js",
    "content": "import ColorHash from 'color-hash';\n\nconst colorHash = new (ColorHash.default || ColorHash)({\n  lightness: [0.5, 0.6],\n  saturation: [0.5, 0.6, 0.7],\n  hash: (string) => [...string].reduce((accumulator, char, index) => {\n    return accumulator + ((char.codePointAt() * (index + 1)) ** 2);\n  }, 0),\n});\n\n/**\n * A data store for the fixture register.\n */\nexport class Register {\n  /**\n   * Create a new register instance.\n   * @param {object} manufacturers An object of all known manufacturers like specified by the manufacturer schema.\n   * @param {object | null} register A register object to start with.\n   */\n  constructor(manufacturers, register) {\n    if (register) {\n      this.filesystem = register.filesystem;\n      this.manufacturers = register.manufacturers;\n      this.categories = register.categories;\n      this.contributors = register.contributors;\n      this.rdm = register.rdm;\n      this.colors = register.colors;\n    }\n    else {\n      this.filesystem = {};\n      this.manufacturers = {};\n      this.categories = {};\n      this.contributors = {};\n      this.rdm = {};\n      this.colors = {};\n    }\n\n    this._manufacturerData = manufacturers;\n  }\n\n  /**\n   * Add manufacturer information to the register.\n   * @param {string} manufacturerKey The manufacturer key.\n   * @param {object} manufacturer The manufacturer data like specified by the manufacturer schema.\n   */\n  addManufacturer(manufacturerKey, manufacturer) {\n    if (!(manufacturerKey in this.manufacturers)) {\n      this.manufacturers[manufacturerKey] = [];\n      this.colors[manufacturerKey] = colorHash.hex(manufacturerKey);\n    }\n\n    const rdmId = this._manufacturerData[manufacturerKey].rdmId;\n    if (rdmId && !(rdmId in this.rdm)) {\n      this.rdm[rdmId] = {\n        key: manufacturerKey,\n        models: {},\n      };\n    }\n  }\n\n  /**\n   * Add fixture redirect information to the register.\n   * @param {string} manufacturerKey The manufacturer key.\n   * @param {string} fixtureKey The fixture (redirect) key.\n   * @param {object} redirectData The redirect data like specified by the fixture redirect schema.\n   * @param {object} redirectToData The fixture data of the redirectTo fixture like specified by the fixture schema.\n   */\n  addFixtureRedirect(manufacturerKey, fixtureKey, redirectData, redirectToData) {\n    this.filesystem[`${manufacturerKey}/${fixtureKey}`] = {\n      name: redirectData.name,\n      redirectTo: redirectData.redirectTo,\n      reason: redirectData.reason,\n    };\n\n    if (redirectData.reason === 'SameAsDifferentBrand') {\n      // add to manufacturer register\n      this._addFixtureToManufacturer(manufacturerKey, fixtureKey);\n\n      // add to category register\n      for (const category of redirectToData.categories) {\n        this._addFixtureToCategory(manufacturerKey, fixtureKey, category);\n      }\n    }\n  }\n\n  /**\n   * Add fixture redirect information to the register.\n   * @param {string} manufacturerKey The manufacturer key.\n   * @param {string} fixtureKey The fixture (redirect) key.\n   * @param {object} fixtureData The fixture data like specified by the fixture schema.\n   */\n  addFixture(manufacturerKey, fixtureKey, fixtureData) {\n    const { lastAction, lastActionDate } = getFixtureLastAction(fixtureData.meta);\n\n    // add to filesystem register\n    this.filesystem[`${manufacturerKey}/${fixtureKey}`] = {\n      name: fixtureData.name,\n      lastActionDate,\n      lastAction,\n    };\n\n    // add to manufacturer register\n    this._addFixtureToManufacturer(manufacturerKey, fixtureKey);\n\n    // add to category register\n    for (const category of fixtureData.categories) {\n      this._addFixtureToCategory(manufacturerKey, fixtureKey, category);\n    }\n\n    // add to contributor register\n    for (const contributor of fixtureData.meta.authors) {\n      this._addFixtureToContributor(manufacturerKey, fixtureKey, contributor, lastActionDate);\n    }\n\n    // add to rdm register\n    if ('rdm' in fixtureData && 'rdmId' in this._manufacturerData[manufacturerKey]) {\n      const rdmManufacturerId = this._manufacturerData[manufacturerKey].rdmId;\n      const rdmModelId = fixtureData.rdm.modelId;\n      this.rdm[rdmManufacturerId].models[rdmModelId] = fixtureKey;\n    }\n  }\n\n  /**\n   * @private\n   * @param {string} manufacturerKey The manufacturer key.\n   * @param {string} fixtureKey The fixture (redirect) key.\n   */\n  _addFixtureToManufacturer(manufacturerKey, fixtureKey) {\n    if (!(manufacturerKey in this.manufacturers)) {\n      this.manufacturers[manufacturerKey] = [];\n    }\n    this.manufacturers[manufacturerKey].push(fixtureKey);\n  }\n\n  /**\n   * @private\n   * @param {string} manufacturerKey The manufacturer key.\n   * @param {string} fixtureKey The fixture (redirect) key.\n   * @param {string} category The category to add this fixture to.\n   */\n  _addFixtureToCategory(manufacturerKey, fixtureKey, category) {\n    if (!(category in this.categories)) {\n      this.categories[category] = [];\n    }\n    this.categories[category].push(`${manufacturerKey}/${fixtureKey}`);\n  }\n\n  /**\n   * @private\n   * @param {string} manufacturerKey The manufacturer key.\n   * @param {string} fixtureKey The fixture (redirect) key.\n   * @param {string} contributor The contributor to add this fixture to.\n   * @param {string} lastActionDate The most recent action of the added fixture.\n   */\n  _addFixtureToContributor(manufacturerKey, fixtureKey, contributor, lastActionDate) {\n    if (contributor in this.contributors) {\n      this.contributors[contributor].fixtures.push(`${manufacturerKey}/${fixtureKey}`);\n\n      if (lastActionDate > this.contributors[contributor].lastActionDate) {\n        this.contributors[contributor].lastActionDate = lastActionDate;\n      }\n    }\n    else {\n      this.contributors[contributor] = {\n        lastActionDate,\n        fixtures: [`${manufacturerKey}/${fixtureKey}`],\n      };\n    }\n  }\n\n  /**\n   * @returns {object} The sorted register.\n   */\n  getAsSortedObject() {\n    const sortedRegister = {\n      filesystem: getObjectSortedByKeys(this.filesystem),\n      manufacturers: getObjectSortedByKeys(this.manufacturers, (fixtures) => fixtures.toSorted(localeSort)),\n      categories: getObjectSortedByKeys(this.categories, (fixtures) => fixtures.toSorted(localeSort)),\n      contributors: {},\n      rdm: {},\n      colors: getObjectSortedByKeys(this.colors),\n      lastUpdated: [],\n    };\n\n    // copy sorted contributors into register\n    const sortedContributors = Object.keys(this.contributors).toSorted((nameA, nameB) => {\n      const lastActionA = this.contributors[nameA].lastActionDate;\n      const lastActionB = this.contributors[nameB].lastActionDate;\n\n      // people with more recent contributions should come first\n      if (lastActionA !== lastActionB) {\n        return lastActionA > lastActionB ? -1 : 1;\n      }\n\n      return localeSort(nameA, nameB);\n    }).filter((contributor) => contributor !== 'Anonymous');\n    for (const contributor of sortedContributors) {\n      sortedRegister.contributors[contributor] = {\n        lastActionDate: this.contributors[contributor].lastActionDate,\n        fixtures: this.contributors[contributor].fixtures.toSorted(localeSort),\n      };\n    }\n\n    // if the dates are the same, the last action with higher priority\n    // (which appears first in this array) is sorted before the other fixture\n    const lastActionPriority = ['created', 'imported', 'modified'];\n\n    // add fixture list sorted by lastActionDate\n    sortedRegister.lastUpdated = Object.keys(this.filesystem).filter(\n      (fixtureKey) => 'lastActionDate' in this.filesystem[fixtureKey],\n    ).toSorted((fixtureKeyA, fixtureKeyB) => {\n      const fixtureA = this.filesystem[fixtureKeyA];\n      const fixtureB = this.filesystem[fixtureKeyB];\n\n      // most recently edited fixtures should come first\n      const dateDelta = new Date(fixtureB.lastActionDate) - new Date(fixtureA.lastActionDate);\n      if (dateDelta !== 0) {\n        return dateDelta;\n      }\n\n      // if date is the same, look at what changed\n      const actionDelta = lastActionPriority.indexOf(fixtureA.lastAction) - lastActionPriority.indexOf(fixtureB.lastAction);\n      if (actionDelta !== 0) {\n        return actionDelta;\n      }\n\n      return localeSort(fixtureKeyA, fixtureKeyB);\n    });\n\n    // copy sorted RDM data into register\n    for (const manufacturerId of Object.keys(this.rdm).toSorted(localeSort)) {\n      sortedRegister.rdm[manufacturerId] = {\n        key: this.rdm[manufacturerId].key,\n        models: getObjectSortedByKeys(this.rdm[manufacturerId].models),\n      };\n    }\n\n    return sortedRegister;\n  }\n}\n\n/**\n * @param {object} object The object to sort.\n * @param {((value: unknown) => unknown) | null} itemMapFunction A function to be invoked for every object value to process it (useful to sort array values).\n * @returns {object} A new object with the same entries, sorted by keys.\n */\nexport function getObjectSortedByKeys(object, itemMapFunction) {\n  const sortedObject = {};\n  const keys = Object.keys(object).toSorted(localeSort);\n\n  for (const key of keys) {\n    sortedObject[key] = itemMapFunction?.(object[key]) ?? object[key];\n  }\n\n  return sortedObject;\n}\n\n/**\n * Function to pass into Array.sort().\n * @param {string} a The first string.\n * @param {string} b The second string.\n * @returns {number} A number indicating the order of the two strings.\n */\nfunction localeSort(a, b) {\n  return a.localeCompare(b, 'en', {\n    numeric: true,\n  });\n}\n\n/**\n * @param {object} fixtureMeta The fixture's meta object.\n * @returns {object} The fixture's last action and last action data.\n */\nfunction getFixtureLastAction(fixtureMeta) {\n  if ('importPlugin' in fixtureMeta && new Date(fixtureMeta.lastModifyDate) <= new Date(fixtureMeta.importPlugin.date)) {\n    return {\n      lastAction: 'imported',\n      lastActionDate: fixtureMeta.importPlugin.date,\n    };\n  }\n\n  return {\n    lastAction: fixtureMeta.lastModifyDate === fixtureMeta.createDate ? 'created' : 'modified',\n    lastActionDate: fixtureMeta.lastModifyDate,\n  };\n}\n"
  },
  {
    "path": "lib/scale-dmx-values.js",
    "content": "/**\n * @param {number} dmxValue The original DMX value in the given current resolution.\n * @param {number} currentResolution The current resolution (1 for 8bit, 2 for 16bit, etc.) of the given DMX value.\n * @param {number} desiredResolution The desired resolution (1 for 8bit, 2 for 16bit, etc.) of the returned DMX value.\n * @returns {number} The original DMX value, scaled to the desired resolution.\n */\nexport function scaleDmxValue(dmxValue, currentResolution, desiredResolution) {\n  const bytes = getBytes(dmxValue, currentResolution);\n\n  while (currentResolution < desiredResolution) {\n    bytes.push(bytes[currentResolution - 1]);\n    currentResolution++;\n  }\n\n  while (currentResolution > desiredResolution) {\n    bytes.length--; // remove last byte\n    currentResolution--;\n  }\n\n  return bytesToDmxValue(bytes);\n}\n\n/**\n * @param {number} dmxRangeStart The range's DMX start value in the given current resolution.\n * @param {number} dmxRangeEnd The range's DMX end value in the given current resolution.\n * @param {number} currentResolution The current resolution (1 for 8bit, 2 for 16bit, etc.) of the given DMX values.\n * @param {number} desiredResolution The desired resolution (1 for 8bit, 2 for 16bit, etc.) of the returned DMX range.\n * @returns {[number, number]} The DMX start / end values, scaled to the desired resolution.\n */\nexport function scaleDmxRange(dmxRangeStart, dmxRangeEnd, currentResolution, desiredResolution) {\n  return scaleDmxRangeIndividually(dmxRangeStart, currentResolution, dmxRangeEnd, currentResolution, desiredResolution);\n}\n\n/**\n * @param {number} dmxRangeStart The range's DMX start value in the given current resolution.\n * @param {number} startResolution The current resolution (1 for 8bit, 2 for 16bit, etc.) of the given DMX start value.\n * @param {number} dmxRangeEnd The range's DMX end value in the given current resolution.\n * @param {number} endResolution The current resolution (1 for 8bit, 2 for 16bit, etc.) of the given DMX end value.\n * @param {number} desiredResolution The desired resolution (1 for 8bit, 2 for 16bit, etc.) of the returned DMX range.\n * @returns {[number, number]} The DMX start / end values, scaled to the desired resolution.\n */\nexport function scaleDmxRangeIndividually(dmxRangeStart, startResolution, dmxRangeEnd, endResolution, desiredResolution) {\n  let startBytes = getBytes(dmxRangeStart, startResolution);\n  const endBytes = getBytes(dmxRangeEnd, endResolution);\n\n  while (endResolution < desiredResolution) {\n    endBytes.push(255);\n    endResolution++;\n  }\n  while (startResolution < desiredResolution) {\n    startBytes.push(0);\n    startResolution++;\n  }\n\n  while (endResolution > desiredResolution) {\n    endBytes.length--; // remove last end byte\n    endResolution--;\n  }\n  while (startResolution > desiredResolution) {\n    const deletedStartByte = startBytes[startResolution - 1];\n\n    startBytes.length--; // remove last start byte\n    startResolution--;\n\n    // increase start value by 1 if the deleted start byte was non-zero and if this won't make the range invalid\n    if (deletedStartByte > 0 && bytesToDmxValue(startBytes) < bytesToDmxValue(endBytes)) {\n      startBytes = getBytes(bytesToDmxValue(startBytes) + 1, startResolution);\n    }\n  }\n\n  return [bytesToDmxValue(startBytes), bytesToDmxValue(endBytes)];\n}\n\n/**\n * @param {number[]} bytes The individual channel values as 8bit numbers.\n * @returns {number} The combined DMX value.\n */\nfunction bytesToDmxValue(bytes) {\n  let dmxValue = 0;\n\n  for (const [index, byte] of bytes.entries()) {\n    dmxValue += byte * Math.pow(256, bytes.length - index - 1);\n  }\n\n  return dmxValue;\n}\n\n/**\n * @param {number} dmxValue A DMX value in the given resolution.\n * @param {number} resolution The resolution (1 for 8bit, 2 for 16bit, etc.) of the given DMX value.\n * @returns {number[]} The DMX value, splitted into the individual channel values. Coarsest value first.\n */\nfunction getBytes(dmxValue, resolution) {\n  const bytes = [];\n\n  while (resolution > 0) {\n    const byte = dmxValue % 256;\n    bytes.push(byte);\n    dmxValue = (dmxValue - byte) / 256;\n    resolution--;\n  }\n\n  if (dmxValue > 0) {\n    throw new Error('Given DMX value was outside the given resolution');\n  }\n\n  bytes.reverse();\n\n  return bytes;\n}\n"
  },
  {
    "path": "lib/schema-properties.js",
    "content": "import {\n  capabilitySchema,\n  channelSchema,\n  definitionsSchema,\n  fixtureRedirectSchema,\n  fixtureSchema,\n  manufacturersSchema,\n  wheelSlotSchema,\n} from '../lib/esm-shim.cjs';\n\nexport const fixtureProperties = fixtureSchema.properties;\nexport const physicalProperties = fixtureProperties.physical.properties;\n\nexport const capabilityTypes = Object.fromEntries(capabilitySchema.oneOf.map(\n  (schema) => [schema.properties.type.const, schema],\n));\n\nexport const wheelSlotTypes = Object.fromEntries(wheelSlotSchema.oneOf.map(\n  (schema) => [schema.properties.type.const, schema],\n));\n\nexport const manufacturerProperties = manufacturersSchema.additionalProperties.properties;\nexport const fixtureRedirectProperties = fixtureRedirectSchema.properties;\nexport const linksProperties = fixtureProperties.links.properties;\nexport const physicalBulbProperties = physicalProperties.bulb.properties;\nexport const physicalLensProperties = physicalProperties.lens.properties;\nexport const modeProperties = fixtureProperties.modes.items.properties;\nexport const channelProperties = channelSchema.properties;\nexport const capabilityDmxRange = capabilitySchema.definitions.dmxRange;\nexport const schemaDefinitions = definitionsSchema;\nexport const unitsSchema = definitionsSchema.units;\nexport const entitiesSchema = definitionsSchema.entities;\n"
  },
  {
    "path": "lib/server-response-helpers.js",
    "content": "/** @import { ServerResponse } from 'http' */\n\n/**\n * @param {ServerResponse} response The Node ServerResponse object.\n * @param {object} jsonObject The JSON object to send.\n */\nexport function sendJson(response, jsonObject) {\n  response.setHeader('Content-Type', 'application/json');\n  response.end(JSON.stringify(jsonObject));\n}\n\n/**\n * @param {ServerResponse} response The Node ServerResponse object.\n * @param {object} file The file attachment.\n * @param {string} file.name The name of the file attachment. Use ASCII characters only to avoid incompabilities.\n * @param {string} file.mimetype The MIME type to set.\n * @param {string | Buffer} file.content The content of the file attachment.\n */\nexport function sendAttachment(response, { name, mimetype, content }) {\n  response.setHeader('Content-Type', mimetype);\n  response.setHeader('Content-Disposition', `attachment; filename=\"${name}\"`);\n  response.end(content);\n}\n"
  },
  {
    "path": "lib/site-crawler.js",
    "content": "import childProcess from 'child_process';\nimport brokenLinkChecker from 'broken-link-checker';\nimport terminate from 'terminate/promise';\nimport importJson from './import-json.js';\n\nconst BASE_URL = `http://localhost:${process.env.PORT || 3000}`;\n\n/**\n * @emits passingPage The URL of a passing (internal) page.\n * @emits failingPage The URL of a failing (internal) page and an error string.\n * @emits externalLinkFound The URL of an external link.\n */\nexport default class SiteCrawler extends EventTarget {\n  /**\n   * Starts the production OFL server by creating a new child process.\n   * Make sure that 'npm run build' has been called before this function is executed!\n   * @returns {Promise} Promise that resolves as soon as the OFL server is up and running, or rejects if the process stops with an error before.\n   */\n  async startServer() {\n    const onServerData = new Promise((resolve, reject) => {\n      // Remove TEST so that nuxt's showBanner() isn't suppressed (vitest sets TEST=true)\n      const childEnv = { ...process.env, NODE_ENV: 'production' };\n      delete childEnv.TEST;\n\n      this.serverProcess = childProcess.execFile('npx', ['nuxt', 'start'], {\n        env: childEnv,\n      }, (error, stdout, stderr) => {\n        // when server has been stopped\n\n        if (error && !error.killed) {\n          reject(error);\n          return;\n        }\n\n        // save stdout and stderr so that they can be returned by stopServer()\n        this.serverStdout = stdout;\n        this.serverStderr = stderr;\n      });\n\n      // wait until server has started\n      this.serverProcess.stdout.on('data', (output) => {\n        if (output.includes('Listening on:')) {\n          resolve();\n        }\n      });\n    });\n    await onServerData;\n  }\n\n  /**\n   * Emits a custom event.\n   * @param {string} eventName Name of the event.\n   * @param {string} url URL of the page that is related to the event.\n   * @param {string | undefined} error Message that is related to the event.\n   */\n  emit(eventName, url, error) {\n    const event = new Event(eventName);\n    event.url = url;\n    event.error = error;\n    this.dispatchEvent(event);\n  }\n\n  /**\n   * Crawls the local deployment. Updates about crawled pages are given using events.\n   * @returns {Promise} Promise that resolves as soon as the crawling has finished.\n   */\n  async crawl() {\n    const { exportPlugins } = await importJson('../plugins/plugins.json', import.meta.url);\n\n    return new Promise((resolve, reject) => {\n      const siteChecker = new brokenLinkChecker.SiteChecker({\n        excludeExternalLinks: true,\n        filterLevel: 3,\n        honorRobotExclusions: false,\n        maxSocketsPerHost: 10,\n        rateLimit: 25,\n\n        excludedKeywords: [\n          // form targets are not meant to be called without parameters / with GET instead of POST\n          `${BASE_URL}/api/*`,\n\n          // large fixtures shouldn't be tested twice\n          '*?loadAllModes',\n\n          // Exports are excluded as they are no real pages and take too long to load.\n          // They are tested by exports-valid script.\n          ...exportPlugins.map((pluginKey) => `${BASE_URL}/*.${pluginKey}`),\n        ],\n      },\n      {\n        html: (tree, robots, response, pageUrl, customData) => {\n          // HTML page successfully retrieved and rendered\n\n          this.emit('passingPage', pageUrl);\n        },\n        junk: (result, customData) => {\n          // new link on current HTML page discovered, but skipped\n\n          if (!result.internal && result.url.resolved !== null) {\n            this.emit('externalLinkFound', result.url.resolved);\n          }\n        },\n        link: (result, customData) => {\n          // new link on current HTML page discovered and fetched\n\n          const allowedStatusCodes = [200, 301, 302];\n          if (result.http.response !== null && !allowedStatusCodes.includes(result.http.response.statusCode)) {\n            this.emit('failingPage', result.url.resolved, `${result.http.response.statusCode} ${result.http.response.statusMessage}`);\n          }\n          else if (result.broken) {\n            this.emit('failingPage', result.url.resolved, result.brokenReason);\n          }\n        },\n        page: (error, pageUrl, customData) => {\n          // all links of current HTML page have been tested\n          // this is also called if the first page errored\n\n          if (error) {\n            this.emit('failingPage', pageUrl, error);\n          }\n        },\n        end: () => {\n          resolve();\n        },\n      });\n\n      siteChecker.enqueue(BASE_URL);\n    });\n  }\n\n  /**\n   * Kills the server process.\n   * @returns {Promise<object>} Promise that resolves with stdout and stderr as soon as the server process is closed.\n   */\n  async stopServer() {\n    await terminate(this.serverProcess.pid);\n\n    return { stdout: this.serverStdout, stderr: this.serverStderr };\n  }\n}\n"
  },
  {
    "path": "lib/types.js",
    "content": "// needed for VS Code to import typedefs from this file\nexport default null;\n\n/**\n * @typedef {object} FixtureCreateResult\n * @property {Record<string, object>} manufacturers Manufacturer keys pointing to manufacturer JSON objects.\n * @property {Record<string, object>} fixtures 'manufacturerKey/fixtureKey' combinations pointing to fixture JSON objects.\n * @property {Record<string, string[]>} warnings 'manufacturerKey/fixtureKey' combinations pointing to fixture's warnings.\n * @property {Record<string, string[]>} errors 'manufacturerKey/fixtureKey' combinations pointing to fixture's errors.\n */\n"
  },
  {
    "path": "nuxt.config.js",
    "content": "import { fileURLToPath } from 'url';\nimport sass from 'sass';\nimport register from './fixtures/register.json';\nimport { fixtureFromRepository } from './lib/model.js';\nimport plugins from './plugins/plugins.json';\n\nconst ignoredSassDeprecations = ['legacy-js-api']; // can only be fixed with Nuxt.js v3\nconst sassDeprecationIds = Object.values(sass.deprecations).flatMap((deprecation) =>\n  (deprecation.status === 'active' && !ignoredSassDeprecations.includes(deprecation.id) ? [deprecation.id] : []),\n);\n\nconst websiteUrl = process.env.WEBSITE_URL || `http://localhost:${process.env.PORT || 3000}/`;\n\nexport default {\n  telemetry: true,\n  srcDir: './ui/',\n  modules: [\n    ['@nuxtjs/axios', {\n      browserBaseURL: '/',\n    }],\n    'nuxt-helmet',\n    'cookie-universal-nuxt',\n    '@nuxtjs/robots',\n    '@nuxtjs/sitemap',\n  ],\n  plugins: [\n    '~/plugins/global-components.js',\n    '~/plugins/vue-form.js',\n  ],\n  serverMiddleware: [\n    {\n      path: '/api/v1',\n      handler: '~/api/index.js',\n    },\n    {\n      path: '/',\n      handler: '~/api/download.js',\n    },\n  ],\n  helmet: {\n    expectCt: false,\n    hsts: {\n      maxAge: 2 * 365 * 24 * 60 * 60,\n      preload: true,\n    },\n    crossOriginEmbedderPolicy: false, // needed for Embetty poster images and video iframes\n  },\n  css: [\n    '~/assets/styles/style.scss',\n    'embetty-vue/dist/embetty-vue.css',\n  ],\n  publicRuntimeConfig: {\n    websiteUrl,\n    searchIndexingIsAllowed: process.env.ALLOW_SEARCH_INDEXING === 'allowed',\n  },\n  build: {\n    quiet: false,\n    loaders: {\n      // condense whitespace in Vue templates\n      vue: {\n        compilerOptions: {\n          whitespace: 'condense',\n        },\n      },\n      // automatically `@use` global SCSS definitions\n      scss: {\n        additionalData: '@use \"~/assets/styles/global.scss\" as *;',\n        sassOptions: {\n          fatalDeprecations: sassDeprecationIds,\n          silenceDeprecations: ignoredSassDeprecations,\n        },\n      },\n    },\n    transpile: ['a11y-dialog', 'embetty-vue', 'uuid', 'vue-ts-types'],\n    babel: {\n      plugins: ['@babel/plugin-transform-logical-assignment-operators'],\n    },\n    extend(config, context) {\n      // uuid v14 removed the `main` field and uses only `exports`, which webpack 4 doesn't support\n      config.resolve.alias.uuid = fileURLToPath(new URL('node_modules/uuid/dist/index.js', import.meta.url));\n\n      // exclude /assets/icons from url-loader\n      const iconsPath = fileURLToPath(new URL('ui/assets/icons/', import.meta.url));\n      const urlLoader = config.module.rules.find((rule) => rule.test.toString().includes('|svg|'));\n      urlLoader.exclude = iconsPath;\n\n      // include /assets/icons for svg-inline-loader\n      config.module.rules.push({\n        test: /\\.svg$/,\n        include: [iconsPath],\n        loader: 'svg-inline-loader',\n        options: {\n          removeSVGTagAttrs: false,\n        },\n      });\n    },\n  },\n  render: {\n    csp: {\n      policies: {\n        'default-src': ['\\'none\\''],\n        'script-src': ['\\'unsafe-eval\\''], // needed because of https://github.com/nuxt/nuxt.js/pull/7454\n        'style-src': ['\\'self\\'', '\\'unsafe-inline\\''],\n        'img-src': ['\\'self\\'', 'https://*.open-fixture-library.org', 'https://*.ytimg.com', 'data:'],\n        'frame-src': ['\\'self\\'', 'https://*.vimeo.com', '*.youtube-nocookie.com', 'https://www.facebook.com'],\n        'font-src': ['\\'self\\''],\n        'connect-src': ['\\'self\\''],\n        'manifest-src': ['\\'self\\''],\n        'media-src': ['*'], // allow all videos\n        'form-action': ['\\'self\\''],\n        'frame-ancestors': ['\\'none\\''],\n        'object-src': ['\\'none\\''],\n        'base-uri': ['\\'self\\''],\n      },\n    },\n  },\n  loading: {\n    color: '#1e88e5',\n  },\n  head() {\n    const theme = this.$cookies.get('__Host-theme') || this.$cookies.get('theme');\n    const htmlAttributes = {\n      'lang': 'en',\n      'data-theme': theme,\n    };\n\n    const titleTemplate = (titleChunk) => {\n      // If undefined or blank then we don't need the hyphen\n      return titleChunk ? `${titleChunk} – Open Fixture Library` : 'Open Fixture Library';\n    };\n\n    const canonicalUrl = this.$config.websiteUrl.slice(0, -1) + this.$route.path.replace(/\\/$/, ''); // remove trailing slash\n\n    const meta = [\n      {\n        charset: 'utf-8',\n      },\n      {\n        name: 'viewport',\n        content: 'width=device-width, initial-scale=1.0',\n      },\n      {\n        name: 'mobile-web-app-capable',\n        content: 'yes',\n      },\n      {\n        hid: 'theme-color',\n        name: 'theme-color',\n        content: theme === 'dark' ? '#383838' : '#fafafa', // SCSS: theme-color(header-background)\n      },\n      {\n        // this enables Twitter link previews\n        name: 'twitter:card',\n        content: 'summary',\n      },\n      {\n        hid: 'url',\n        property: 'og:url',\n        content: canonicalUrl,\n      },\n      {\n        hid: 'type',\n        property: 'og:type',\n        content: 'website',\n      },\n      {\n        hid: 'site_name',\n        property: 'og:site_name',\n        content: 'Open Fixture Library',\n      },\n      {\n        hid: 'locale',\n        property: 'og:locale',\n        content: 'en_US',\n      },\n      {\n        hid: 'determiner',\n        property: 'og:determiner',\n        content: 'the',\n      },\n      {\n        hid: 'description',\n        property: 'og:description',\n        content: 'Create and browse fixture definitions for lighting equipment online and download them in the right format for your DMX control software!',\n      },\n      {\n        hid: 'title',\n        property: 'og:title',\n        content: '',\n        template: titleTemplate,\n      },\n      {\n        hid: 'image',\n        property: 'og:image',\n        content: 'https://open-fixture-library.org/open-graph.png',\n      },\n      {\n        hid: 'image_type',\n        property: 'og:image:type',\n        content: 'image/png',\n      },\n      {\n        hid: 'image_width',\n        property: 'og:image:width',\n        content: '1280',\n      },\n      {\n        hid: 'image_height',\n        property: 'og:image:height',\n        content: '640',\n      },\n    ];\n\n    if (!this.$config.searchIndexingIsAllowed) {\n      meta.push({\n        name: 'robots',\n        content: 'noindex, nofollow, none, noodp, noarchive, nosnippet, noimageindex, noydir, nocache',\n      });\n    }\n\n    const link = [\n      {\n        rel: 'canonical',\n        href: canonicalUrl,\n      },\n      {\n        rel: 'apple-touch-icon',\n        sizes: '180x180',\n        href: '/apple-touch-icon.png',\n      },\n      {\n        rel: 'icon',\n        type: 'image/png',\n        href: '/favicon-32x32.png',\n        sizes: '32x32',\n      },\n      {\n        rel: 'icon',\n        type: 'image/png',\n        href: '/favicon-16x16.png',\n        sizes: '16x16',\n      },\n      {\n        rel: 'manifest',\n        href: '/manifest.json',\n      },\n      {\n        rel: 'mask-icon',\n        href: '/safari-pinned-tab.svg',\n        color: '#64b5f6',\n      },\n      {\n        rel: 'preload',\n        href: '/fonts/LatoLatin/LatoLatin-Regular.woff2',\n        as: 'font',\n        type: 'font/woff2',\n      },\n    ];\n\n    return {\n      htmlAttrs: htmlAttributes,\n      titleTemplate,\n      meta,\n      link,\n    };\n  },\n  robots() {\n    if (process.env.ALLOW_SEARCH_INDEXING !== 'allowed') {\n      return {\n        UserAgent: '*',\n        Disallow: '/',\n      };\n    }\n\n    return {\n      UserAgent: '*',\n      Disallow: plugins.exportPlugins.map((pluginKey) => `/*.${pluginKey}$`),\n      Allow: '/',\n      Sitemap: `${websiteUrl}sitemap.xml`,\n    };\n  },\n  sitemap: {\n    hostname: websiteUrl,\n    gzip: true,\n    async routes() {\n      const staticUrls = [\n        { url: '/', changefreq: 'daily' },\n        { url: '/fixture-editor', changefreq: 'monthly' },\n        { url: '/import-fixture-file', changefreq: 'monthly' },\n        { url: '/manufacturers', changefreq: 'monthly' },\n        { url: '/categories', changefreq: 'monthly' },\n        { url: '/about', changefreq: 'monthly' },\n        { url: '/about/plugins', changefreq: 'monthly' },\n        { url: '/rdm', changefreq: 'yearly' },\n        { url: '/search', changefreq: 'yearly' },\n      ];\n\n      const manufacturerUrlPromises = Object.keys(register.manufacturers).flatMap((manufacturerKey) => [\n        Promise.resolve({ url: `/${manufacturerKey}`, changefreq: 'weekly' }),\n\n        // fixture URLs\n        ...register.manufacturers[manufacturerKey].map(async (fixtureKey) => {\n          const fixture = await fixtureFromRepository(manufacturerKey, fixtureKey);\n          return {\n            url: `/${manufacturerKey}/${fixtureKey}`,\n            changefreq: 'monthly',\n            lastmod: fixture.meta.lastModifyDate.toISOString(),\n          };\n        }),\n      ]);\n\n      const categoryUrls = Object.keys(register.categories).map(\n        (category) => ({ url: `/categories/${category}`, changefreq: 'weekly' }),\n      );\n\n      const pluginUrls = Object.keys(plugins.data).filter((key) => !plugins.data[key].outdated).map(\n        (pluginKey) => ({ url: `/about/plugins/${pluginKey}`, changefreq: 'monthly' }),\n      );\n\n      return [\n        ...staticUrls,\n        ...await Promise.all(manufacturerUrlPromises),\n        ...categoryUrls,\n        ...pluginUrls,\n      ];\n    },\n  },\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"open-fixture-library\",\n  \"version\": \"1.0.0\",\n  \"description\": \"An open source library for lighting technology's fixture definition files\",\n  \"author\": \"Florian Edelmann <flo@open-fixture-library.org>\",\n  \"contributors\": [\n    \"Felix Edelmann <fxedel@gmail.com>\"\n  ],\n  \"engines\": {\n    \"node\": \"24.x\",\n    \"npm\": \"11.x\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"nuxt dev\",\n    \"start\": \"nuxt start\",\n\n    \"build\": \"npm run build-without-nuxt && npm run build:nuxt\",\n    \"build-without-nuxt\": \"npm run build:register && npm run build:plugin-data && npm run build:test-fixtures && npm run build:model-docs && npm run build:api-docs\",\n    \"build:nuxt\": \"nuxt build\",\n    \"build:register\": \"node cli/build-register.js\",\n    \"build:plugin-data\": \"node cli/build-plugin-data.js\",\n    \"build:test-fixtures\": \"node cli/build-test-fixtures.js\",\n    \"build:model-docs\": \"jsdoc2md --private --files lib/model/*.js > docs/model-api.md\",\n    \"build:api-docs\": \"widdershins --code true --language_tabs --omitBody true --omitHeader true --resolve true --outfile docs/rest-api.md ui/api/openapi.json && eslint --fix docs/rest-api.md\",\n\n    \"clean\": \"rm -rf .nuxt tmp\",\n    \"update-package-lock\": \"rm package-lock.json && npm install && npm audit fix && npx update-browserslist-db@latest\",\n\n    \"lint\": \"npm run lint:eslint && npm run lint:stylelint\",\n    \"lint:eslint\": \"eslint --cache\",\n    \"lint:eslint-errors-only\": \"eslint --cache --quiet\",\n    \"lint:stylelint\": \"stylelint **/*.scss **/*.vue\",\n\n    \"test\": \"npm run lint && npm run test:fixtures-valid\",\n    \"test:dmx-value-scaling\": \"vitest run tests/dmx-value-scaling.test.js\",\n    \"test:fixtures-valid\": \"node tests/fixtures-valid.js -a\",\n    \"test:http-status\": \"vitest run tests/http-status.test.js\",\n    \"test:built-files-committed\": \"node tests/built-files-committed.js\"\n  },\n  \"dependencies\": {\n    \"@heise/embetty-server\": \"^2.0.3\",\n    \"@nuxtjs/axios\": \"^5.13.6\",\n    \"@nuxtjs/robots\": \"^2.5.0\",\n    \"@nuxtjs/sitemap\": \"^2.4.0\",\n    \"@octokit/rest\": \"~22.0.1\",\n    \"a11y-dialog\": \"^8.1.5\",\n    \"ajv\": \"^8.20.0\",\n    \"ajv-formats\": \"^3.0.1\",\n    \"color-hash\": \"^2.0.2\",\n    \"color-name-list\": \"^14.36.0\",\n    \"cookie-universal-nuxt\": \"^2.2.2\",\n    \"cors\": \"^2.8.6\",\n    \"embetty-vue\": \"^2.2.2\",\n    \"express\": \"^5.2.1\",\n    \"jszip\": \"^3.10.1\",\n    \"node-env-file\": \"^0.1.8\",\n    \"nuxt\": \"~2.18.1\",\n    \"nuxt-helmet\": \"^3.0.0\",\n    \"openapi-backend\": \"^5.16.1\",\n    \"sanitize-filename\": \"^1.6.4\",\n    \"sass\": \"^1.99.0\",\n    \"sass-loader\": \"^10.5.2\",\n    \"scroll-into-view\": \"^1.16.2\",\n    \"svg-inline-loader\": \"^0.8.2\",\n    \"uuid\": \"^14.0.0\",\n    \"vue-form\": \"^4.10.3\",\n    \"vue-ts-types\": \"^1.9.0\",\n    \"vuedraggable\": \"^2.24.3\",\n    \"xml2js\": \"^0.6.2\",\n    \"xmlbuilder\": \"^15.1.1\"\n  },\n  \"devDependencies\": {\n    \"@eslint/compat\": \"^2.0.5\",\n    \"@eslint/js\": \"~9.39.3\",\n    \"@eslint/markdown\": \"~8.0.1\",\n    \"@stylistic/eslint-plugin\": \"~5.10.0\",\n    \"@stylistic/stylelint-config\": \"~5.0.0\",\n    \"@vitest/eslint-plugin\": \"^1.6.16\",\n    \"broken-link-checker\": \"^0.7.8\",\n    \"dir-compare\": \"^5.0.0\",\n    \"disparity\": \"^3.2.0\",\n    \"eslint\": \"~9.39.3\",\n    \"eslint-plugin-import\": \"~2.32.0\",\n    \"eslint-plugin-jsdoc\": \"~62.7.1\",\n    \"eslint-plugin-jsonc\": \"~3.1.2\",\n    \"eslint-plugin-nuxt\": \"~4.0.0\",\n    \"eslint-plugin-promise\": \"~7.3.0\",\n    \"eslint-plugin-sonarjs\": \"~4.0.3\",\n    \"eslint-plugin-unicorn\": \"~64.0.0\",\n    \"eslint-plugin-vue\": \"~10.9.0\",\n    \"eslint-plugin-vuejs-accessibility\": \"~2.5.0\",\n    \"globals\": \"^17.6.0\",\n    \"jsdoc-to-markdown\": \"^9.1.3\",\n    \"libxml2-wasm\": \"^0.7.1\",\n    \"minimist\": \"^1.2.8\",\n    \"postcss-html\": \"^1.8.1\",\n    \"stylelint\": \"~17.10.0\",\n    \"stylelint-config-html\": \"~1.1.0\",\n    \"stylelint-config-recess-order\": \"~7.7.0\",\n    \"stylelint-config-standard-scss\": \"~17.0.0\",\n    \"stylelint-order\": \"~8.1.1\",\n    \"terminate\": \"^2.8.0\",\n    \"vitest\": \"^4.1.5\",\n    \"vue-eslint-parser\": \"~10.4.0\",\n    \"widdershins\": \"^4.0.1\"\n  },\n  \"homepage\": \"https://open-fixture-library.org/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/OpenLightingProject/open-fixture-library\"\n  },\n  \"keywords\": [\n    \"dmx\",\n    \"dmx512\",\n    \"ecue\",\n    \"fixture\",\n    \"fixtures\",\n    \"lighting\",\n    \"qlc\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "plugins/aglight/export.js",
    "content": "/* Based on the ofl export plugin */\n\nimport fixtureJsonStringify from '../../lib/fixture-json-stringify.js';\nimport importJson from '../../lib/import-json.js';\nimport Entity from '../../lib/model/Entity.js';\nimport NullChannel from '../../lib/model/NullChannel.js';\n/** @import Fixture from '../../lib/model/Fixture.js' */\n\nconst units = new Set(['K', 'deg', '%', 'ms', 'Hz', 'm^3/min', 'rpm']);\nconst excludeKeys = new Set(['comment', 'name', 'helpWanted', 'type', 'effectName', 'effectPreset', 'shutterEffect', 'wheel', 'isShaking', 'fogType', 'menuClick']);\n\n// see https://github.com/OpenLightingProject/open-fixture-library/issues/4415\nconst colorNameListPromise = importJson('../../node_modules/color-name-list/dist/colornames.json', import.meta.url);\n\nexport const version = '1.0.0';\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const displayedPluginVersion = options.displayedPluginVersion || version;\n\n  const [manufacturers, namedColors] = await Promise.all([\n    importJson('../../fixtures/manufacturers.json', import.meta.url),\n    colorNameListPromise,\n  ]);\n\n  const library = {\n    version: displayedPluginVersion,\n    fixtures: fixtures.map((fixture) => {\n      try {\n        return exportFixture(fixture, manufacturers, namedColors);\n      }\n      catch (error) {\n        throw new Error(`Exporting fixture ${fixture.manufacturer.key}/${fixture.key} failed: ${error}`, {\n          cause: error,\n        });\n      }\n    }),\n  };\n  return [{\n    name: 'aglight_fixture_library.json',\n    content: fixtureJsonStringify(library),\n    mimetype: 'application/aglight-fixture-library',\n    fixtures,\n  }];\n}\n\n/**\n * @param {Fixture} fixture The fixture to export.\n * @param {object} manufacturers The manufacturers object.\n * @param {object[]} namedColors The color names list.\n * @returns {object} The generated fixture JSON.\n */\nfunction exportFixture(fixture, manufacturers, namedColors) {\n  const jsonData = structuredClone(fixture.jsonObject);\n  jsonData.fixtureKey = fixture.key;\n  jsonData.manufacturer = manufacturers[fixture.manufacturer.key];\n  jsonData.oflURL = fixture.url;\n\n  if (!jsonData.availableChannels) {\n    jsonData.availableChannels = {};\n  }\n\n  downgradePhysical(jsonData.physical);\n  transformMatrixChannels(jsonData, fixture);\n  transformSingleCapabilityToArray(jsonData);\n  transformNonNumericValues(jsonData, namedColors);\n\n  for (const mode of jsonData.modes) {\n    downgradePhysical(mode.physical);\n  }\n\n  return jsonData;\n}\n\n/**\n * Removes `powerConnectors` from physical.\n * @param {object|undefined} physicalJsonData The physical object to transform.\n */\nfunction downgradePhysical(physicalJsonData) {\n  if (physicalJsonData) {\n    delete physicalJsonData.powerConnectors;\n  }\n}\n\n/**\n * Resolves matrix channels in modes' channel lists.\n * It also adds the resolved template channels to `availableChannels` and adds a `pixelKey` property.\n * @param {object} fixtureJson The fixture JSON object where the resolved matrix channels should be saved to.\n * @param {Fixture} fixture The fixture whose template channels should be resolved.\n */\nfunction transformMatrixChannels(fixtureJson, fixture) {\n  for (const [index, mode] of fixture.modes.entries()) {\n    fixtureJson.modes[index].channels = mode.channelKeys;\n  }\n\n  const availableAndMatrixChannels = fixture.coarseChannels.filter(\n    (channel) => !(channel instanceof NullChannel),\n  );\n\n  fixtureJson.availableChannels = Object.fromEntries(\n    availableAndMatrixChannels.map((channel) => {\n      let channelJsonObject = structuredClone(channel.jsonObject);\n\n      if (channel.pixelKey) {\n        channelJsonObject = {\n          ...channelJsonObject,\n          pixelKey: channel.pixelKey,\n        };\n      }\n\n      return [channel.key, channelJsonObject];\n    }),\n  );\n\n  delete fixtureJson.templateChannels;\n}\n\n/**\n * All channels with a single capability are converted to `capabilities: [capability]`,\n * and a `singleCapability` attribute with the value true is added.\n * @param {object} fixtureJson The fixture whose channels should be processed\n */\nfunction transformSingleCapabilityToArray(fixtureJson) {\n  for (const channel of Object.values(fixtureJson.availableChannels)) {\n    if (channel.capability) {\n      channel.capabilities = [channel.capability];\n      channel.singleCapability = true;\n      delete channel.capability;\n    }\n  }\n}\n\n/**\n * Replace capability properties' entity strings with unitless numbers, and\n * ColorIntensity capabilities' color property with its hex value.\n * @param {object} fixtureJson The fixture whose capabilities should be processed\n * @param {object[]} namedColors The color names list.\n */\nfunction transformNonNumericValues(fixtureJson, namedColors) {\n  for (const channel of Object.values(fixtureJson.availableChannels)) {\n    for (const capability of channel.capabilities) {\n      for (const [key, value] of Object.entries(capability)) {\n        if (key === 'color') {\n          processColor(capability, namedColors);\n        }\n        else if (typeof value === 'string' && !excludeKeys.has(key)) {\n          capability[key] = getEntityNumber(value);\n        }\n      }\n    }\n  }\n}\n\n/**\n * @param {object} capability The capability where the color name in the color attribute should be replaced with its hex value\n * @param {object[]} namedColors The color names list.\n */\nfunction processColor(capability, namedColors) {\n  const namedColor = namedColors.find((color) => color.name === capability.color);\n  if (namedColor && namedColor.hex) {\n    capability.color = namedColor.hex;\n  }\n  else {\n    // If the color was not found, just ignore it\n    // console.log(`#### color not found`, capability.color);\n  }\n}\n\n/**\n * @param {string} entityString The property value where the entity number should be extracted from.\n * @returns {number | string} A unitless number, or the original property value if it can't be parsed as an entity.\n */\nfunction getEntityNumber(entityString) {\n  try {\n    const entity = Entity.createFromEntityString(entityString);\n\n    if (entity.keyword !== null) {\n      return entityString;\n    }\n\n    if (entity.unit === 's') {\n      return entity.number * 1000;\n    }\n\n    if (units.has(entity.unit)) {\n      return entity.number;\n    }\n  }\n  catch {\n    // string could not be parsed as an entity\n  }\n\n  return entityString;\n}\n"
  },
  {
    "path": "plugins/aglight/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"AGLight\",\n  \"description\": [\n    \"<p><em>AGLight</em> is a lighting software with a completely configurable UI.\",\n    \"You can add different widgets and build your own user interface with drag and drop.</p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://github.com/hrueger/AGLight/\"\n  },\n  \"fixtureUsage\": [\n    \"<p>You don't need to download the fixtures, just click on the library button in the bottom statusbar and click update.</p>\",\n    \"<p>However, if the device you run AGLight on is not connected to the internet,\",\n    \"you can also copy the exported fixture library to that device.\",\n    \"See below for the directory paths. You need to rename the file to <code>library.json</code>.</p>\"\n  ],\n  \"fileLocations\": {\n    \"subDirectoriesAllowed\": false,\n    \"Windows\": {\n      \"user\": \"C:\\\\Users\\\\yourUsername\\\\AppData\\\\Roaming\\\\aglight\\\\library\\\\library.json\"\n    },\n    \"Mac OS\": {\n      \"user\": \"~/Library/Application Support/aglight/library/library.json\"\n    },\n    \"Linux\": {\n      \"user\": \"~/.config/aglight/library/library.json\"\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/color-chief/export.js",
    "content": "import CoarseChannel from '../../lib/model/CoarseChannel.js';\nimport SwitchingChannel from '../../lib/model/SwitchingChannel.js';\n/** @import AbstractChannel from '../../lib/model/AbstractChannel.js' */\n/** @import Fixture from '../../lib/model/Fixture.js' */\n/** @import Mode from '../../lib/model/Mode.js' */\n\n/**\n * @typedef {object} ModeChannels\n * @property {SegmentChannels[]} segments The channels of all the fixture's segments.\n * @property {AbstractChannel[]} colorWheels The fixture's color wheel channels.\n * @property {AbstractChannel[]} freePatchChannels The fixture's free patch channels.\n */\n\n/**\n * @typedef {object} SegmentChannels\n * @property {AbstractChannel | undefined} red The segment's red channel.\n * @property {AbstractChannel | undefined} green The segment's green channel.\n * @property {AbstractChannel | undefined} blue The segment's blue channel.\n * @property {AbstractChannel | undefined} white The segment's white channel.\n * @property {AbstractChannel | undefined} amber The segment's amber channel.\n * @property {AbstractChannel | undefined} uv The segment's UV channel.\n * @property {AbstractChannel | undefined} dimmer The segment's dimmer channel.\n * @property {AbstractChannel | undefined} shutter The segment's shutter/strobe channel.\n */\n\nexport const version = '1.0.0';\n\nconst segmentsPerFile = 4;\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  return fixtures.flatMap((fixture) => fixture.modes.flatMap((mode) => {\n    try {\n      return getFilesForMode(mode);\n    }\n    catch (error) {\n      throw new Error(`Exporting fixture mode ${fixture.manufacturer.key}/${fixture.key}/${mode.shortName} failed: ${error}`, {\n        cause: error,\n      });\n    }\n  }));\n}\n\n/**\n * @param {Mode} mode The mode to export.\n * @returns {object[]} The generated files for this mode.\n */\nfunction getFilesForMode(mode) {\n  const modeChannels = getModeChannels(mode);\n\n  const totalFiles = Math.ceil(modeChannels.segments.length / segmentsPerFile);\n\n  return Array.from({ length: totalFiles }).flatMap((_, fileIndex) => {\n    const channels = getChannelsForFile(modeChannels, fileIndex);\n\n    const magicNumber = [0x08, 0x00, 0x04, 0x08, 0x00, 0x04, 0x08, 0x00, 0x04];\n    const versionCode = 0x01;\n    const channelIndices = Object.values(channels).map((channel) => (channel === undefined ? 0x3D : mode.getChannelIndex(channel.key) + 1));\n    const padding = Array.from({ length: 154 }, () => 0x00);\n\n    const byteArray = new Uint8Array([\n      ...magicNumber,\n      versionCode,\n      ...channelIndices,\n      ...padding,\n    ]);\n\n    const descriptionFileContent = Object.entries(channels).map(([controlElement, channel]) => {\n      const channelName = channel?.name ?? '–';\n      return `${controlElement}: ${channelName}`;\n    }).join('\\n');\n\n    return [\n      {\n        name: getFileName(mode, totalFiles, fileIndex, 'lib'),\n        content: Buffer.from(byteArray),\n        mimetype: 'binary/octet-stream',\n        fixtures: [mode.fixture],\n        modes: [mode],\n      },\n      {\n        name: getFileName(mode, totalFiles, fileIndex, 'txt'),\n        content: descriptionFileContent,\n        mimetype: 'text/plain',\n        fixtures: [mode.fixture],\n        modes: [mode],\n      },\n    ];\n  });\n}\n\n/**\n * @param {Mode} mode The mode to select the channels from.\n * @returns {ModeChannels} The selected mode channels.\n */\nfunction getModeChannels(mode) {\n  const channelsByPixelKey = groupModeChannelsByPixelKey(mode);\n  const segments = channelsByPixelKey.map((channels) => ({\n    red: channels.find((channel) => isColorChannel(channel, 'Red')),\n    green: channels.find((channel) => isColorChannel(channel, 'Green')),\n    blue: channels.find((channel) => isColorChannel(channel, 'Blue')),\n    white: channels.find((channel) => isColorChannel(channel, 'White') || isColorChannel(channel, 'Cold White') || isColorChannel(channel, 'Warm White')),\n    amber: channels.find((channel) => isColorChannel(channel, 'Amber') || isColorChannel(channel, 'Warm White')),\n    uv: channels.find((channel) => isColorChannel(channel, 'UV')),\n    dimmer: channels.find((channel) => isChannelOfType(channel, 'Intensity')),\n    shutter: channels.find((channel) => isChannelOfType(channel, 'Strobe') || isChannelOfType(channel, 'Shutter')),\n  }));\n\n  mergeDisjunctSegments(segments);\n\n  return {\n    segments,\n    colorWheels: mode.channels.filter((channel) => isChannelOfType(channel, 'Multi-Color')),\n    freePatchChannels: [\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Pan')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Tilt')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Effect')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Gobo')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Speed')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Prism')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'WheelSlotRotation')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Zoom')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Iris')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Color Temperature')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Maintenance')),\n      ...mode.channels.filter((channel) => isChannelOfType(channel, 'Shutter') && segments.every(\n        (segment) => segment.shutter !== channel,\n      )),\n    ],\n  };\n}\n\n/**\n * @param {Mode} mode The mode to get the segments for.\n * @returns {AbstractChannel[][]} The mode's channels, grouped by the pixel key they belong to.\n */\nfunction groupModeChannelsByPixelKey(mode) {\n  const channelsByPixelKey = {};\n\n  for (const channel of mode.channels) {\n    if (!(channel.pixelKey in channelsByPixelKey)) {\n      channelsByPixelKey[channel.pixelKey] = [];\n    }\n    channelsByPixelKey[channel.pixelKey].push(channel);\n  }\n\n  return Object.values(channelsByPixelKey);\n}\n\n/**\n * Try to merge consecutive segments with disjunctly defined control elements.\n * @param {SegmentChannels[]} segments The segments to merge.\n */\nfunction mergeDisjunctSegments(segments) {\n  let segmentIndex = 1;\n\n  while (segmentIndex < segments.length) {\n    const currentSegment = segments[segmentIndex];\n    const previousSegment = segments[segmentIndex - 1];\n    const definedControlElements = Object.keys(currentSegment).filter(\n      (controlElement) => currentSegment[controlElement] !== undefined,\n    );\n    const canBeMerged = definedControlElements.every(\n      (controlElement) => previousSegment[controlElement] === undefined,\n    );\n\n    if (canBeMerged) {\n      for (const controlElement of definedControlElements) {\n        previousSegment[controlElement] = currentSegment[controlElement];\n      }\n      segments.splice(segmentIndex, 1);\n    }\n    else {\n      segmentIndex++;\n    }\n  }\n}\n\n/**\n * @param {AbstractChannel} channel The channel to check.\n * @param {string} color The color to check.\n * @returns {boolean} Whether the channel is a color channel with the given color.\n */\nfunction isColorChannel(channel, color) {\n  if (channel instanceof SwitchingChannel) {\n    channel = channel.defaultChannel;\n  }\n\n  return channel instanceof CoarseChannel && channel.color === color;\n}\n\n/**\n * @param {AbstractChannel} channel The channel to check.\n * @param {string} type The type to check.\n * @returns {boolean} Whether the channel is a channel with the given type.\n */\nfunction isChannelOfType(channel, type) {\n  if (channel instanceof SwitchingChannel) {\n    channel = channel.defaultChannel;\n  }\n\n  return channel instanceof CoarseChannel && channel.type === type;\n}\n\n/**\n * @param {Mode} mode The mode to get the file name for.\n * @param {number} totalFiles The total number of files for this mode.\n * @param {number} fileIndex The index of the file in this mode's files.\n * @param {'lib' | 'txt'} extension The file extension.\n * @returns {string} The file name.\n */\nfunction getFileName(mode, totalFiles, fileIndex, extension) {\n  const fileNumberSuffix = totalFiles === 1 ? '' : `_${fileIndex + 1}_of_${totalFiles}`;\n  return `${mode.fixture.manufacturer.key}_${mode.fixture.key}_${mode.shortName}${fileNumberSuffix}.${extension}`;\n}\n\n/**\n * @param {ModeChannels} modeChannels The mode's selected and grouped channels.\n * @param {number} fileIndex The index of the file in this mode's files.\n * @returns {Record<string, AbstractChannel | undefined>} The channels in the order they should appear in the file.\n */\nfunction getChannelsForFile(modeChannels, fileIndex) {\n  const fileChannels = {};\n\n  const fileSegments = modeChannels.segments.slice(fileIndex * segmentsPerFile, (fileIndex + 1) * segmentsPerFile);\n  for (let segmentIndex = 0; segmentIndex < segmentsPerFile; segmentIndex++) {\n    const channels = segmentIndex < fileSegments.length ? fileSegments[segmentIndex] : undefined;\n    fileChannels[`Red ${segmentIndex + 1}`] = channels?.red;\n    fileChannels[`Green ${segmentIndex + 1}`] = channels?.green;\n    fileChannels[`Blue ${segmentIndex + 1}`] = channels?.blue;\n    fileChannels[`White ${segmentIndex + 1}`] = channels?.white;\n    fileChannels[`Amber ${segmentIndex + 1}`] = channels?.amber;\n    fileChannels[`UV ${segmentIndex + 1}`] = channels?.uv;\n    fileChannels[`Dimmer ${segmentIndex + 1}`] = channels?.dimmer;\n    fileChannels[`Shutter ${segmentIndex + 1}`] = channels?.shutter;\n  }\n\n  fileChannels['Color Wheel'] = modeChannels.colorWheels[fileIndex];\n\n  const freePatchChannelsPerFile = 3;\n  fileChannels['FP 1'] = modeChannels.freePatchChannels[(fileIndex * freePatchChannelsPerFile) + 0];\n  fileChannels['FP 2'] = modeChannels.freePatchChannels[(fileIndex * freePatchChannelsPerFile) + 1];\n  fileChannels['FP 3'] = modeChannels.freePatchChannels[(fileIndex * freePatchChannelsPerFile) + 2];\n\n  return fileChannels;\n}\n"
  },
  {
    "path": "plugins/color-chief/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"Eurolite Color Chief 2.0\",\n  \"description\": [\n    \"<p>The <em>Color Chief</em> DMX controller offers an innovative control\",\n    \"concept combining easy handling with astounding results. It has been\",\n    \"developed especially for both colored spot lights and simpler light\",\n    \"effects. Altogether, the Color Chief can control a total of 8 spot lights\",\n    \"with up to 4 segments each.</p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://www.steinigke.de/en/mpn70064575-eurolite-dmx-led-color-chief-controller.html\",\n    \"Manual, software and library download\": \"https://www.steinigke.de/en/mpn70064575-eurolite-dmx-led-color-chief-controller.html#support\",\n    \"Fixture format documentation\": \"https://github.com/OpenLightingProject/open-fixture-library/issues/684#issuecomment-939321680\"\n  },\n  \"fixtureUsage\": [\n    \"<p>Place the downloaded <code>*.lib</code> fixture files into a folder\",\n    \"called <code>COLORCHIEF</code> in the root of the USB stick.<br>\",\n    \"The corresponding <code>*.txt</code> files are a human readable form\",\n    \"of how the channels are mapped to the control elements.</p>\"\n  ],\n  \"helpWanted\": \"Is it possible for multiple patched fixtures to have the same DMX start address in the Color Chief configuration? This is currently needed for large fixture modes that occupy more than 4 segments, e.g. Showtec Pixel Bar 12 MKII's RGB Individual mode.\"\n}\n"
  },
  {
    "path": "plugins/colorsource/export.js",
    "content": "import { v5 as uuidv5 } from 'uuid';\nimport CoarseChannel from '../../lib/model/CoarseChannel.js';\nimport FineChannel from '../../lib/model/FineChannel.js';\nimport SwitchingChannel from '../../lib/model/SwitchingChannel.js';\nimport { scaleDmxValue } from '../../lib/scale-dmx-values.js';\n\nexport const version = '0.1.0';\n\nconst EDITOR_VERSION = '1.1.1.9.0.4';\n\nconst CHANNEL_TYPE_NO_FUNCTION = 0;\nconst CHANNEL_TYPE_INTENSITY = 1;\nconst CHANNEL_TYPE_POSITION = 2;\nconst CHANNEL_TYPE_MULTI_COLOR = 3;\nconst CHANNEL_TYPE_BEAM = 4;\nconst CHANNEL_TYPE_COLOR = 5;\n\nconst UUID_NAMESPACE = '0de81b51-02b2-45e3-b53c-578f9eb31b77'; // seed for UUIDs\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date | null} options.date The current time.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const exportJson = {\n    date: options.date.toISOString().replace(/\\.\\d{3}Z$/, 'Z'),\n    editorVersion: EDITOR_VERSION,\n    personalities: [],\n  };\n\n  for (const fixture of fixtures) {\n    const fixtureUuidNamespace = uuidv5(`${fixture.manufacturer.key}/${fixture.key}`, UUID_NAMESPACE);\n\n    for (const mode of fixture.modes) {\n      exportJson.personalities.push(getColorSourcePersonality(fixture, fixtureUuidNamespace, mode));\n    }\n  }\n\n  return [{\n    name: 'userlib.jlib',\n    content: JSON.stringify(exportJson, null, 2),\n    mimetype: 'application/json',\n    fixtures,\n  }];\n}\n\n/**\n * @param {Fixture} fixture The fixture to export.\n * @param {string} fixtureUuidNamespace The UUID namespace for the fixture.\n * @param {Mode} mode The mode to export.\n * @returns {object} The generated fixture JSON.\n */\nfunction getColorSourcePersonality(fixture, fixtureUuidNamespace, mode) {\n  try {\n    const dcid = uuidv5(mode.name, fixtureUuidNamespace);\n    const hasIntensity = mode.channels.some((channel) => channel.type === 'Intensity');\n    const parameters = getColorSourceChannels(mode, hasIntensity);\n\n    const fixtureJson = {\n      dcid,\n      colortable: getColorTable(parameters) || '11111111-1111-1111-1111-111111111111',\n      commands: getCommands(mode),\n      hasIntensity,\n      manufacturerName: fixture.manufacturer.name,\n      maxOffset: mode.channels.length - 1,\n      modeName: mode.name,\n      modelName: fixture.name,\n      parameters,\n    };\n\n    removeEmptyProperties(fixtureJson);\n\n    return fixtureJson;\n  }\n  catch (error) {\n    throw new Error(`Exporting fixture mode ${fixture.manufacturer.key}/${fixture.key}/${mode.shortName} failed: ${error}`, {\n      cause: error,\n    });\n  }\n}\n\n/**\n * @param {object[]} colorSourceChannels A ColorSource fixture's parameter property.\n * @returns {string | null} The UUID of a suitable color table or null if no color table fits.\n */\nfunction getColorTable(colorSourceChannels) {\n  const colorChannels = colorSourceChannels.filter((channel) => channel.type === CHANNEL_TYPE_COLOR);\n\n  const colorTables = {\n    '373673E3-571E-4CE2-B12D-CDD44085A1EB': ['Red', 'Green', 'Blue', 'Amber', 'Cyan', 'Indigo', 'RedOrange'],\n    '02A2F87C-AB4C-41F5-8779-A51B99D0BE1C': ['Red', 'Green', 'Blue', 'White', 'Amber', 'Cyan', 'Indigo'],\n    '75FEB905-EA2A-4643-B4F8-1A84141F8E98': ['Red', 'Green', 'Blue', 'Amber', 'Cyan', 'Indigo', 'Lime'],\n    'EDDEAC65-BD2E-4D87-B163-D7A2434EC081': ['Red', 'Green', 'Blue', 'White', 'Amber', 'UV'],\n    '04493BB0-7B6E-4B6C-B3B7-D9641F7511AD': ['Red', 'Green', 'Blue', 'Cyan', 'Indigo'],\n    '91189886-6A6A-47CF-9137-5F5A7A88D829': ['Red', 'Green', 'Amber', 'Indigo', 'RedOrange'],\n    'C7A1FB0A-AA23-468F-9060-AC1625155DE8': ['Red', 'Green', 'Blue', 'White', 'Amber'],\n    '1D16DE15-5F4C-46A9-9C3D-2380C2D2793A': ['Red', 'Green', 'Blue', 'Amber', 'Indigo'],\n    '3F90A9F9-209F-4505-A9F2-FEC17BC6A426': ['Red', 'Green', 'Blue', 'Amber', 'Cyan'],\n    'B28E1514-AE8C-4E06-8472-B52D575B1CF2': ['Red', 'Green', 'Blue', 'White', 'UV'],\n    '77597794-7BFF-46A3-878B-906D3780E6C9': ['Red', 'Blue', 'White', 'Indigo'],\n    '77A82F8A-9B24-4C3F-98FC-B6A29FB1AAE6': ['Red', 'Green', 'Blue', 'White'],\n    '74EF89F4-0B78-4DC6-8E8A-68E3298B7CD2': ['Red', 'Green', 'Blue', 'UV'],\n    'D3E71EC8-3406-4572-A64C-52A38649C795': ['Red', 'Green', 'Blue', 'Amber'],\n    'B043D095-95A4-4DDB-AB38-252C991B13A8': ['Red', 'Green', 'Blue', 'Indigo'],\n    '3874B444-A11E-47D9-8295-04556EAEBEA7': ['Red', 'Green', 'Blue'],\n    '637E8789-5540-45D5-BD83-D7C2A7618B45': ['Red', 'Green', 'Indigo'],\n    'EF4970BA-2536-4725-9B0F-B2D7A021E139': ['Cyan', 'Magenta', 'Yellow'],\n    'E6AC63D6-1349-4BFC-9A04-7548D1DB8E1F': ['CoolWhite', 'MediumWhite', 'WarmWhite'],\n    '7B365530-A4DF-44AD-AEF5-225472BE02AE': ['CoolWhite', 'WarmWhite'],\n    'B074A2D3-0C40-45A7-844A-7C2721E0B267': ['Hue', 'Saturation'],\n  };\n\n  let selectedColorTable = Object.keys(colorTables).find(\n    (colorTable) => colorTables[colorTable].every(\n      (color) => colorChannels.some((channel) => channel.name === color),\n    ),\n  );\n\n  const has16bitHue = colorChannels.some((channel) => channel.name === 'Hue' && channel.size === 16);\n  if (selectedColorTable === 'B074A2D3-0C40-45A7-844A-7C2721E0B267' && has16bitHue) {\n    // this is a special case; it refers to Hue / Hue fine / Saturation\n    selectedColorTable = 'B3D05F0E-FB45-4EEA-A8D5-61F545A922DE';\n  }\n\n  return selectedColorTable || null;\n}\n\n/**\n * @param {Mode} mode The personality's mode.\n * @returns {object[]} Array of ColorSource commands (e. g. set channel X to value Y after Z seconds), may be empty. The commands are generated by Maintenance capabilities with hold time set.\n */\nfunction getCommands(mode) {\n  const commands = [];\n  for (const [channelIndex, channel] of mode.channels.entries()) {\n    if (!channel.capabilities) {\n      // e. g. fine channels\n      continue;\n    }\n\n    for (const capability of channel.capabilities) {\n      if (capability.type === 'Maintenance' && capability.hold) {\n        commands.push({\n          name: capability.comment,\n          steps: [\n            {\n              actions: [{\n                dmx: channelIndex,\n                value: capability.getMenuClickDmxValueWithResolution(CoarseChannel.RESOLUTION_8BIT),\n              }],\n              wait: 0, // this is apparently the delay before this step is activated\n            },\n            {\n              actions: [{\n                dmx: channelIndex,\n                value: -1,\n              }],\n              wait: capability.hold.baseUnitEntity.number,\n            },\n          ],\n        });\n      }\n    }\n  }\n\n  return commands;\n}\n\n/**\n * @param {Mode} mode The personality's mode.\n * @param {boolean} hasIntensity Whether the mode has an intensity channel. Should be equal to `fixtureJson.hasIntensity`.\n * @returns {object[]} ColorSource channel objects of all mode channels.\n */\nfunction getColorSourceChannels(mode, hasIntensity) {\n  return mode.channels.flatMap((channel, channelIndex) => {\n    const name = channel.name;\n\n    if (channel instanceof SwitchingChannel) {\n      channel = channel.defaultChannel;\n    }\n\n    const channelJson = {\n      coarse: channelIndex,\n      fadeWithIntensity: false,\n      fine: null,\n      highlight: 65_535,\n      home: 0,\n      invert: false,\n      name,\n      ranges: [],\n      size: 8,\n      snap: false,\n      type: getColorSourceChannelType(channel),\n    };\n\n    if (channelJson.type === CHANNEL_TYPE_COLOR) {\n      if (isMatrixChannel(channel)) {\n        channelJson.type = CHANNEL_TYPE_BEAM;\n      }\n      else if (channel.color) { // it may also be Hue or Saturation, which have no color\n        channelJson.name = channel.color.replaceAll(' ', ''); // e.g. 'Warm White' -> 'WarmWhite'\n      }\n    }\n\n    if (channel instanceof FineChannel) {\n      if (channel.resolution === CoarseChannel.RESOLUTION_16BIT) {\n        // already handled by \"fine\" attribute of coarse channel\n        return [];\n      }\n\n      channelJson.type = CHANNEL_TYPE_BEAM;\n      channelJson.home = scaleDmxValue(channel.defaultValue, CoarseChannel.RESOLUTION_8BIT, CoarseChannel.RESOLUTION_16BIT);\n    }\n    else {\n      addColorSourceChannelDetails(channelJson, channel);\n    }\n\n    removeEmptyProperties(channelJson);\n\n    return [channelJson];\n  });\n\n  /**\n   * Adds information to given channel JSON that is specific to (and only makes sense for) coarse channels.\n   * @param {object} channelJson The ColorSource channel JSON to which the data is added.\n   * @param {CoarseChannel} channel The OFL channel whose information should be used.\n   */\n  function addColorSourceChannelDetails(channelJson, channel) {\n    channelJson.fadeWithIntensity = channel.type === 'Single Color' && hasIntensity;\n\n    const fineChannel16bit = channel.fineChannels[0];\n    const fineChannelIndex = fineChannel16bit ? mode.getChannelIndex(fineChannel16bit.key, 'default') : -1;\n    if (fineChannelIndex !== -1) {\n      channelJson.fine = fineChannelIndex;\n      channelJson.size = 16;\n    }\n\n    const channelResolution = channelJson.size / 8;\n    channelJson.highlight = scaleDmxValue(\n      channel.getHighlightValueWithResolution(channelResolution),\n      channelResolution,\n      CoarseChannel.RESOLUTION_16BIT,\n    );\n    channelJson.home = scaleDmxValue(\n      channel.getDefaultValueWithResolution(channelResolution),\n      channelResolution,\n      CoarseChannel.RESOLUTION_16BIT,\n    );\n\n    channelJson.invert = channel.isInverted;\n    channelJson.snap = !channel.canCrossfade;\n\n    if (channelJson.type !== CHANNEL_TYPE_NO_FUNCTION) {\n      channelJson.ranges = channel.capabilities.map((capability) => {\n        const dmxRange = capability.getDmxRangeWithResolution(CoarseChannel.RESOLUTION_8BIT);\n        const capabilityJson = {\n          begin: dmxRange.start,\n          default: capability.getMenuClickDmxValueWithResolution(CoarseChannel.RESOLUTION_8BIT),\n          end: dmxRange.end,\n          label: capability.name,\n        };\n\n        if (capability.colors && capability.colors.allColors.length === 1) {\n          const color = capability.colors.allColors[0]; // `#rrggbb`\n          capabilityJson.media = {\n            r: Number.parseInt(color.slice(1, 3), 16),\n            g: Number.parseInt(color.slice(3, 5), 16),\n            b: Number.parseInt(color.slice(5, 7), 16),\n          };\n        }\n\n        return capabilityJson;\n      });\n    }\n  }\n\n  /**\n   * @param {CoarseChannel} channel The OFL channel whose information should be used.\n   * @returns {boolean} Whether the channel belongs to a pixel or pixel group that is not the master pixel group.\n   */\n  function isMatrixChannel(channel) {\n    if (!channel.pixelKey) {\n      return false;\n    }\n\n    const matrix = mode.fixture.matrix;\n    const isPixelGroup = matrix.pixelGroupKeys.includes(channel.pixelKey);\n    const isMasterPixelGroup = isPixelGroup && matrix.pixelGroups[channel.pixelKey].length === matrix.pixelKeys.length;\n\n    return !isMasterPixelGroup;\n  }\n}\n\n/**\n * @param {AbstractChannel} channel The OFL channel of which the ColorSource channel type should be returned.\n * @returns {number} One of ColorSource's channel types as positive integer.\n */\nfunction getColorSourceChannelType(channel) {\n  if (channel.type === 'NoFunction') {\n    return CHANNEL_TYPE_NO_FUNCTION;\n  }\n\n  if (channel.type === 'Single Color' || ['Hue', 'Saturation'].includes(channel.name)) {\n    return CHANNEL_TYPE_COLOR;\n  }\n\n  if (channel.type === 'Intensity') {\n    return CHANNEL_TYPE_INTENSITY;\n  }\n\n  if (isTypePosition()) {\n    return CHANNEL_TYPE_POSITION;\n  }\n\n  if (['Multi-Color', 'Color Temperature'].includes(channel.type)) {\n    return CHANNEL_TYPE_MULTI_COLOR;\n  }\n\n  return CHANNEL_TYPE_BEAM;\n\n  /**\n   * @returns {boolean} Whether the channel is pan, tilt or pan/tilt speed.\n   */\n  function isTypePosition() {\n    if (['Pan', 'Tilt'].includes(channel.type)) {\n      return true;\n    }\n\n    return (channel.capabilities || []).some((capability) => capability.type === 'PanTiltSpeed');\n  }\n}\n\n/**\n * Removes null values and empty arrays from the given object.\n * This function is destructive, i.e. it mutates the given object.\n * @param {object} object The object whose properties should be cleaned up.\n */\nfunction removeEmptyProperties(object) {\n  for (const [key, value] of Object.entries(object)) {\n    if (value === null || (Array.isArray(value) && value.length === 0)) {\n      delete object[key];\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/colorsource/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"ColorSource\",\n  \"description\": [\n    \"<p>\",\n    \"ColorSource (CS) is a series of DMX consoles by ETC.\",\n    \"The installed fixture library is not available in a readable format,\",\n    \"but custom fixtures created using the Personality Editor are saved as JSON files.\",\n    \"</p>\",\n    \"<p>\",\n    \"You can download the ColorSource Offline program that simulates the console if you\",\n    \"don't have physical access to one; see Downloads below.\",\n    \"</p>\"\n  ],\n  \"links\": {\n    \"Console product page\": \"https://www.etcconnect.com/Products/Consoles/ColorSource/Features.aspx\",\n    \"Downloads (including Personality Editor)\": \"https://www.etcconnect.com/Products/Consoles/ColorSource/Software.aspx\",\n    \"Console Manual\": \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737496502\",\n    \"Personality Editor manual\": \"https://www.etcconnect.com/WorkArea/DownloadAsset.aspx?id=10737490177\"\n  },\n  \"fixtureUsage\": [\n    \"<p>\",\n    \"Load the <code>userlib.jlib</code> onto the root of a USB drive and plug it into the console\",\n    \"(or into your computer, if you use ColorSource Offline).\",\n    \"When patching devices, select \\\"User Library\\\" instead of \\\"Standard Library\\\".\",\n    \"</p>\"\n  ],\n  \"fileLocations\": {\n    \"subDirectoriesAllowed\": false,\n    \"USB drive (for console)\": {\n      \"user\": \"/userlib.jlib\"\n    }\n  },\n  \"additionalInfo\": [\n    \"<h3>ColorSource channel types</h3>\",\n    \"\",\n    \"<table>\",\n    \"<tr>\",\n    \"  <th scope=\\\"col\\\">CS type</th>\",\n    \"  <th scope=\\\"col\\\">Description</th>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>0</code></td>\",\n    \"  <td>No function / Hidden</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>1</code></td>\",\n    \"  <td>Intensity</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>2</code></td>\",\n    \"  <td>Pan, Tilt, PanTiltSpeed</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>3</code></td>\",\n    \"  <td>Color wheel, ColorPreset, ColorTemperature</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>4</code></td>\",\n    \"  <td>\\\"Beam\\\" – basically everything that doesn't fit to another type</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>5</code></td>\",\n    \"  <td>Single Color (see below), Hue, Saturation</td>\",\n    \"</tr>\",\n    \"</table>\",\n    \"\",\n    \"<h3>Known colors</h3>\",\n    \"<p>Red, Green, Blue, White (~7500K or unknown temperature), Amber, UV,\",\n    \"Cyan, Magenta, Yellow, Indigo, Lime, Orange, RedOrange, MintGreen, GreenCyan,\",\n    \"CoolWhite (~9000K), MediumWhite (~4000K), WarmWhite (~3200K)</p>\",\n    \"<p>Extracted from <code>C:/Program Files (x86)/ETC/ColorSource/Library/ColorTable.idx</code>.</p>\",\n    \"\",\n    \"\",\n    \"<h3>Features not supported by the Personality Editor</h3>\",\n    \"\",\n    \"<h4>Commands</h4>\",\n    \"<p>\",\n    \"Commands define a sequence of specific DMX values with hold time to perform a certain action, e. g. device reset.\",\n    \"We could (in theory) use this feature to make use of our Maintenance.hold property.\",\n    \"However, commands are used in internal fixtures only,\",\n    \"the .jlib importer seems to simply delete the commands property.\",\n    \"Nevertheless, we include the commands property in our exported fixtures\",\n    \"as the logic to create them has already been implemented and it may be supported in future.\",\n    \"</p>\",\n    \"\",\n    \"<h4>Range tables</h4>\",\n    \"\",\n    \"<p>\",\n    \"Range tables provide a way of defining switching channels.\",\n    \"They aren't supported in .jlib files yet and are preserved for internal fixtures only.\",\n    \"</p>\"\n  ]\n}\n"
  },
  {
    "path": "plugins/d-light/export.js",
    "content": "import sanitize from 'sanitize-filename';\nimport xmlbuilder from 'xmlbuilder';\nimport CoarseChannel from '../../lib/model/CoarseChannel.js';\nimport FineChannel from '../../lib/model/FineChannel.js';\nimport SwitchingChannel from '../../lib/model/SwitchingChannel.js';\n/** @import AbstractChannel from '../../lib/model/AbstractChannel.js' */\n/** @import Capability from '../../lib/model/Capability.js' */\n/** @import Fixture from '../../lib/model/Fixture.js' */\n/** @import Mode from '../../lib/model/Mode.js' */\n\nexport const version = '0.2.0';\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const deviceFiles = [];\n\n  for (const fixture of fixtures) {\n    // add device for each mode\n    for (const mode of fixture.modes) {\n      try {\n        deviceFiles.push(exportFixtureMode(fixture, mode, options));\n      }\n      catch (error) {\n        throw new Error(`Exporting fixture mode ${fixture.manufacturer.key}/${fixture.key}/${mode.shortName} failed: ${error}`, {\n          cause: error,\n        });\n      }\n    }\n  }\n\n  return deviceFiles;\n}\n\n/**\n * @param {Fixture} fixture The fixture to export.\n * @param {Mode} mode The mode to export.\n * @param {object} options Global options.\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {object} The generated file.\n */\nfunction exportFixtureMode(fixture, mode, options) {\n  const xml = xmlbuilder.begin()\n    .declaration('1.0')\n    .element({\n      Device: {\n        // eslint-disable-next-line camelcase -- required by D::Light\n        OFL_Export: {\n          '@id': options.displayedPluginVersion || version,\n          '#text': fixture.url,\n        },\n        frames: {\n          '@id': mode.channels.length,\n        },\n        ManufacturerName: fixture.manufacturer.name,\n        ModelName: `${fixture.name} (${mode.name})`,\n        creationDate: fixture.meta.createDate.toISOString().split('T')[0],\n      },\n    })\n    .element('Attributes');\n\n  // channels are grouped by their channel type which is called AttributesDefinition in D::Light\n  const channelsByAttribute = getChannelsByAttribute(mode.channels);\n  for (const attribute of Object.keys(channelsByAttribute)) {\n    addAttribute(xml, mode, attribute, channelsByAttribute[attribute]);\n  }\n\n  return {\n    name: `${fixture.manufacturer.key}/${fixture.key}-${sanitize(mode.shortName)}.xml`,\n    content: xml.end({\n      pretty: true,\n      indent: '  ',\n    }),\n    mimetype: 'application/xml',\n    fixtures: [fixture],\n    mode: mode.shortName,\n  };\n}\n\n/**\n * Channels are grouped in attributes in D::Light.\n * This function adds the given attribute group along with its channels to the given XML.\n * @param {XMLElement} xml The XML parent element.\n * @param {Mode} mode The fixture's mode that this definition is representing.\n * @param {string} attribute A D::Light attribute name.\n * @param {AbstractChannel[]} channels All channels of the mode that are associated to the given attribute name.\n */\nfunction addAttribute(xml, mode, attribute, channels) {\n  const xmlAttribute = xml.element({\n    AttributesDefinition: {\n      '@id': attribute,\n      '@length': channels.length,\n    },\n  });\n\n  for (let [indexInAttribute, channel] of channels.entries()) {\n    const xmlChannel = xmlAttribute.element({\n      ThisAttribute: {\n        '@id': indexInAttribute,\n        'HOME': {\n          '@id': getDefaultValue(getUsableChannel(channel)),\n        },\n        'addressIndex': {\n          '@id': mode.getChannelIndex(channel.key),\n        },\n        'parameterName': {\n          '@id': getParameterName(channel, mode, attribute, indexInAttribute),\n        },\n        'minLevel': {\n          '@id': 0,\n        },\n        'maxLevel': {\n          '@id': 255,\n        },\n      },\n    });\n\n    channel = getUsableChannel(channel);\n\n    if (channel instanceof CoarseChannel) {\n      const capabilities = channel.capabilities;\n\n      const xmlCapabilities = xmlChannel.element({\n        Definitions: {\n          '@index': capabilities.length,\n        },\n      });\n\n      for (const capability of capabilities) {\n        addCapability(capability, xmlCapabilities);\n      }\n    }\n  }\n}\n\n/**\n * Adds an XML element for the given capability to the XML capability container.\n * @param {Capability} capability A capability of a channels capability list.\n * @param {XMLElement} xmlCapabilities The XML element to add capabilities to.\n */\nfunction addCapability(capability, xmlCapabilities) {\n  let hold = '0';\n\n  if (capability.hold) {\n    if (capability.hold.unit === 'ms') {\n      hold = capability.hold.number;\n    }\n    else if (capability.hold.unit === 's') {\n      hold = capability.hold.number * 1000;\n    }\n  }\n\n  const dmxRange = capability.getDmxRangeWithResolution(CoarseChannel.RESOLUTION_8BIT);\n  xmlCapabilities.element({\n    name: {\n      '@min': dmxRange.start,\n      '@max': dmxRange.end,\n      '@snap': capability.getMenuClickDmxValueWithResolution(CoarseChannel.RESOLUTION_8BIT),\n      '@timeHolder': hold,\n      '@dummy': '0',\n      '#text': capability.name,\n    },\n  });\n}\n\n/**\n * @param {CoarseChannel} channel The channel to get the name for.\n * @param {Mode} mode The mode the channel is in.\n * @param {string} attribute The D::Light attribute name.\n * @param {number} indexInAttribute The index of this channel in the list of all channels related to the attribute.\n * @returns {string} The parameter name (i. e. channel name) that should be used for this channel in D::Light.\n */\nfunction getParameterName(channel, mode, attribute, indexInAttribute) {\n  const uniqueName = channel.uniqueName;\n\n  channel = getUsableChannel(channel);\n\n  if (channel instanceof FineChannel) {\n    // for fine channels, this is simply the coarse channel's index\n    return `${mode.getChannelIndex(channel.coarseChannel.key) + 1}`;\n  }\n\n  if (attribute === 'FOCUS') {\n    return channel.type.toUpperCase(); // PAN or TILT\n  }\n\n  if (attribute === 'INTENSITY' && indexInAttribute === 0 && /dimmer|intensity/i.test(uniqueName)) {\n    return 'DIMMER';\n  }\n\n  // in all other attributes, custom text is allowed\n  // but we need to use another name syntax\n  return uniqueName\n    .toUpperCase()\n    .replaceAll(' ', '_')\n    .replaceAll('/', '|')\n    .replaceAll('COLOR', 'COLOUR');\n}\n\n/**\n * @param {CoarseChannel | FineChannel} channel A usable channel, i. e. no switching channel.\n * @returns {number} The DMX value this channel should be set to as default.\n */\nfunction getDefaultValue(channel) {\n  if (channel instanceof FineChannel) {\n    return channel.defaultValue;\n  }\n\n  return channel.getDefaultValueWithResolution(CoarseChannel.RESOLUTION_8BIT);\n}\n\n/**\n * @param {AbstractChannel} channel Any kind of channel, e.g. an item of a mode's channel list.\n * @returns {CoarseChannel | FineChannel} Switching channels resolved to their default channel.\n */\nfunction getUsableChannel(channel) {\n  if (channel instanceof SwitchingChannel) {\n    return channel.defaultChannel;\n  }\n\n  return channel;\n}\n\n/**\n * @param {AbstractChannel[]} channels List of channels, e.g. from a mode's channel list.\n * @returns {Record<string, AbstractChannel>} D::Light attribute names mapped to the corresponding channels of the given list. All channels are included once.\n */\nfunction getChannelsByAttribute(channels) {\n  const channelsByAttribute = {\n    INTENSITY: [],\n    COLOUR: [],\n    FOCUS: [],\n    BEAM: [],\n    BLADE: [],\n    EFFECT: [],\n    CONTROL: [],\n    EXTRA: [],\n    FINE: [],\n  };\n\n  for (const channel of channels) {\n    channelsByAttribute[getChannelAttribute(getUsableChannel(channel))].push(channel);\n  }\n\n  const emptyAttributes = Object.keys(channelsByAttribute).filter(\n    (attribute) => channelsByAttribute[attribute].length === 0,\n  );\n  for (const emptyAttribute of emptyAttributes) {\n    delete channelsByAttribute[emptyAttribute];\n  }\n\n  return channelsByAttribute;\n\n  /**\n   * @param {CoarseChannel | FineChannel} channel A usable channel, i. e. no matrix or switching channels.\n   * @returns {string} The proper D::Light attribute name for this channel.\n   */\n  function getChannelAttribute(channel) {\n    if (channel instanceof FineChannel) {\n      if (channel.resolution === CoarseChannel.RESOLUTION_16BIT) {\n        return 'FINE';\n      }\n      return 'EXTRA';\n    }\n\n    const oflToDLightMap = {\n      INTENSITY: ['Intensity'],\n      COLOUR: ['Single Color', 'Multi-Color', 'Color Temperature'],\n      FOCUS: ['Pan', 'Tilt'],\n      BEAM: ['Iris', 'Focus', 'Zoom'],\n      EFFECT: ['Strobe', 'Shutter', 'Speed', 'Gobo', 'Prism', 'Effect', 'Fog'],\n      CONTROL: ['Maintenance'],\n      EXTRA: ['NoFunction'],\n    };\n\n    for (const attribute of Object.keys(oflToDLightMap)) {\n      if (oflToDLightMap[attribute].includes(channel.type)) {\n        return attribute;\n      }\n    }\n    return 'EXTRA'; // default if new types are added to OFL\n  }\n}\n"
  },
  {
    "path": "plugins/d-light/exportTests/attributes-correctness.js",
    "content": "import xml2js from 'xml2js';\n\n/**\n * @typedef {object} ExportFile\n * @property {string} name File name, may include slashes to provide a folder structure.\n * @property {string} content File content.\n * @property {string} mimetype File mime type.\n * @property {Fixture[] | null} fixtures Fixture objects that are described in given file; may be omitted if the file doesn't belong to any fixture (e.g. manufacturer information).\n * @property {string | null} mode Mode's shortName if given file only describes a single mode.\n */\n\n/**\n * @param {ExportFile} exportFile The file returned by the plugins' export module.\n * @param {ExportFile[]} allExportFiles An array of all export files.\n * @returns {Promise<void, string[] | string>} Resolve when the test passes or reject with an array of errors or one error if the test fails.\n */\nexport default async function testAttributesCorrectness(exportFile, allExportFiles) {\n  try {\n    const xml = await xml2js.parseStringPromise(exportFile.content);\n    const errors = [];\n\n    const attributeDefinitions = xml.Device.Attributes[0].AttributesDefinition;\n    for (const attributeDefinition of attributeDefinitions) {\n      const usedNames = [];\n      const attributeName = attributeDefinition.$.id;\n\n      for (const attribute of attributeDefinition.ThisAttribute) {\n        const name = attribute.parameterName[0].$.id;\n        if (usedNames.includes(name)) {\n          errors.push(`Duplicate parameter name: ${attributeName}/${name}`);\n        }\n        else {\n          usedNames.push(name);\n        }\n      }\n    }\n\n    if (errors.length > 0) {\n      throw errors;\n    }\n  }\n  catch (parseError) {\n    throw `Error parsing XML: ${parseError.toString()}`;\n  }\n}\n"
  },
  {
    "path": "plugins/d-light/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"D::Light\",\n  \"description\": [\n    \"<p>A lighting software for Windows, Mac OS and Linux.</p>\",\n    \"\",\n    \"<p>There are around 80 fixture definitions (device personalities)\",\n    \"available on the D::Light website. They are stored in a binary format\",\n    \"(<code>.dld</code>), but D::Light also supports non-encrypted fixtures in\",\n    \"an XML format. Thus, creating an import plugin is not possible.</p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://getdlight.com/en/\",\n    \"Device personality download (encrypted)\": \"https://getdlight.com/en/downloaden/28-devices\",\n    \"Fixture help in D::Light Wiki\": \"https://getdlight.com/wiki/index.php?title=DEVICES\",\n    \"Decrypted Robe Robin 600 LEDWash (mode2)\": \"https://pastebin.com/BGmwK1Tw\",\n    \"Decrypted Showtec Phantom 50 (13ch)\": \"https://pastebin.com/QCRa86Xr\"\n  },\n  \"fixtureUsage\": [\n    \"<p>Import fixture in Device Listing window (Devices &gt; Device Listing),\",\n    \"then patch it (Display &gt; Patch).</p>\"\n  ],\n  \"additionalInfo\": [\n    \"<p>The main developer and our contact person is\",\n    \"<a href=\\\"https://github.com/sl1200mk2\\\">sl1200mk2</a>.</p>\"\n  ]\n}\n"
  },
  {
    "path": "plugins/dmxcontrol3/ddf3-function-groups.js",
    "content": "import xmlbuilder from 'xmlbuilder';\n\nexport default [\n  {\n    functions: ['strobe', 'strobespeed'],\n    getXmlGroup: (strobe, strobespeed) => {\n      const xmlStrobe = xmlbuilder.create('strobe');\n      xmlStrobe.attribs = strobespeed.attribs;\n\n      const xmlStrobeType = xmlStrobe.element('strobetype');\n      xmlStrobeType.attribs = strobe.attribs;\n\n      for (const speedCapability of strobespeed.children) {\n        for (const strobeCapability of strobe.children) {\n          if (strobeCapability.attribs.type.value !== 'open') {\n            const xmlSpeedRange = xmlStrobe.element('range');\n            xmlSpeedRange.attribs = { ...speedCapability.attribs };\n            xmlSpeedRange.attribs.type = strobeCapability.attribs.type;\n\n            xmlSpeedRange.element('step', {\n              handler: 'strobetype',\n              mindmx: strobeCapability.attribs.mindmx.value,\n              maxdmx: strobeCapability.attribs.maxdmx.value,\n            });\n          }\n        }\n      }\n\n      return xmlStrobe;\n    },\n  },\n  {\n    functions: ['strobespeed'],\n    getXmlGroup: (strobespeed) => {\n      strobespeed.name = 'strobe';\n      for (const child of strobespeed.children) {\n        child.attribute('type', 'linear');\n      }\n\n      return strobespeed;\n    },\n  },\n  {\n    functions: ['strobe', 'duration'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['pan', 'tilt'],\n    getXmlGroup: mergeIntoNew('position'),\n  },\n  {\n    functions: ['pan'],\n    getXmlGroup: rename('index'),\n  },\n  {\n    functions: ['tilt'],\n    getXmlGroup: rename('index'),\n  },\n  {\n    functions: ['red', 'green', 'blue'],\n    getXmlGroup: mergeIntoNew('rgb'),\n  },\n  {\n    functions: ['cyan', 'magenta', 'yellow'],\n    getXmlGroup: mergeIntoNew('cmy'),\n  },\n  {\n    functions: ['rgb', 'white'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['rgb', 'amber'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['rgb', 'uv'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['rgb', 'cyan'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['rgb', 'yellow'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['rgb', 'lime'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['rgb', 'indigo'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['gobowheel', 'goboindex'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['goboindex'],\n    getXmlGroup: rename('index'),\n  },\n  {\n    functions: ['gobowheel', 'goborotation'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['goborotation'],\n    getXmlGroup: rename('rotation'),\n  },\n  {\n    functions: ['gobowheel', 'goboshake'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['prism', 'prismindex'],\n    getXmlGroup: mergeIntoFirst,\n  },\n  {\n    functions: ['prism', 'prismrotation'],\n    getXmlGroup: mergeIntoFirst,\n  },\n];\n\n/**\n * @param {string} tagName The XML tag name of the new parent element.\n * @returns {(...xmlElements: XMLElement[]) => XMLElement} A function that returns a new XML element with the given elements as children.\n */\nfunction mergeIntoNew(tagName) {\n  return (...xmlElements) => {\n    const xmlParent = xmlbuilder.create(tagName);\n    for (const ele of xmlElements) {\n      xmlParent.importDocument(ele);\n    }\n    return xmlParent;\n  };\n}\n\n/**\n * @param {XMLElement} firstElement The element in which the other elements should be merged into.\n * @param {...XMLElement} xmlElements The elements that should be merge into the first element.\n * @returns {XMLElement} The first element with the other elements as children.\n */\nfunction mergeIntoFirst(firstElement, ...xmlElements) {\n  for (const ele of xmlElements) {\n    firstElement.importDocument(ele);\n  }\n  return firstElement;\n}\n\n/**\n * @param {string} tagName The new XML tag name.\n * @returns {(xmlElement: XMLElement) => XMLElement} A function that alters the given XML element's tag name to the specified new name.\n */\nfunction rename(tagName) {\n  return (xmlElement) => {\n    xmlElement.name = tagName;\n    return xmlElement;\n  };\n}\n"
  },
  {
    "path": "plugins/dmxcontrol3/ddf3-functions.js",
    "content": "import xmlbuilder from 'xmlbuilder';\nimport Capability from '../../lib/model/Capability.js';\nimport CoarseChannel from '../../lib/model/CoarseChannel.js';\n\nexport default {\n  const: {\n    isCapSuitable: (capability) => capability._channel.isConstant,\n    create: (channel, capabilities) => {\n      const xmlConst = xmlbuilder.create('const');\n      xmlConst.attribute('val', channel.getDefaultValueWithResolution(CoarseChannel.RESOLUTION_8BIT));\n      return xmlConst;\n    },\n  },\n  dimmer: {\n    isCapSuitable: (capability) => capability.type === 'Intensity',\n    create: (channel, capabilities) => {\n      const xmlDimmer = xmlbuilder.create('dimmer');\n\n      if (channel.capabilities.length > 1 || capabilities[0].brightness[0].number !== 0) {\n        const dmxControlCapabilities = getSingleUnitCapabilities(capabilities, 'brightness', '%');\n        for (const capability of dmxControlCapabilities) {\n          const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n          xmlCapability.attribute('type', 'linear');\n          xmlDimmer.importDocument(xmlCapability);\n        }\n      }\n\n      return xmlDimmer;\n    },\n  },\n  shutter: {\n    isCapSuitable: (capability) => {\n      const isShutterCapability = capability.type === 'ShutterStrobe' && ['Open', 'Closed'].includes(capability.shutterEffect);\n      const channelHasOpen = capability._channel.capabilities.some((otherCapability) => otherCapability.shutterEffect === 'Open');\n      const channelHasClosed = capability._channel.capabilities.some((otherCapability) => otherCapability.shutterEffect === 'Closed');\n      return isShutterCapability && channelHasOpen && channelHasClosed;\n    },\n    create: (channel, capabilities) => {\n      const xmlShutter = xmlbuilder.create('shutter');\n\n      for (const capability of capabilities) {\n        const xmlCapability = getBaseXmlCapability(capability);\n        xmlCapability.attribute('type', capability.shutterEffect.toLowerCase());\n        xmlShutter.importDocument(xmlCapability);\n      }\n\n      return xmlShutter;\n    },\n  },\n  strobe: {\n    isCapSuitable: (capability) =>\n      (capability.type === 'ShutterStrobe' && !['Open', 'Closed'].includes(capability.shutterEffect))\n      || (capability.type === 'NoFunction' && capability._channel.type === 'Strobe'),\n    create: (channel, capabilities) => {\n      const xmlStrobe = xmlbuilder.create('strobe');\n\n      for (const capability of capabilities) {\n        let xmlCapability;\n\n        if (capability.speed) {\n          const [dmxControlCapability] = getSingleUnitCapabilities([capability], 'speed', 'Hz', 0, 50);\n          xmlCapability = getBaseXmlCapability(capability, dmxControlCapability.startValue, dmxControlCapability.endValue);\n        }\n        else {\n          xmlCapability = getBaseXmlCapability(capability);\n        }\n\n        xmlCapability.attribute('type', getStrobeType(capability));\n        xmlStrobe.importDocument(xmlCapability);\n      }\n\n      return xmlStrobe;\n\n      /**\n       * @param {Capability} capability A ShutterStrobe capability, excluding Open and Closed or a NoFunction capability\n       * @returns {string} The strobe type that should be used in the DMXControl capability.\n       */\n      function getStrobeType(capability) {\n        if (capability.type === 'NoFunction') {\n          return 'open';\n        }\n\n        const typePerShutterEffect = {\n          Strobe: capability.randomTiming ? 'random' : 'linear',\n          RampUp: 'ramp up',\n          RampDown: 'ramp down',\n          RampUpDown: 'ramp up/down',\n        };\n        return typePerShutterEffect[capability.shutterEffect] ?? capability.shutterEffect.toLowerCase();\n      }\n    },\n  },\n  strobeSpeed: {\n    isCapSuitable: (capability) => capability.type === 'StrobeSpeed',\n    create: (channel, capabilities) => {\n      const xmlSpeed = xmlbuilder.create('strobespeed');\n\n      const dmxControlCapabilities = getSingleUnitCapabilities(capabilities, 'speed', 'Hz', 0, 50);\n      for (const capability of dmxControlCapabilities) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlSpeed.importDocument(xmlCapability);\n      }\n\n      return xmlSpeed;\n    },\n  },\n  strobeDuration: {\n    isCapSuitable: (capability) => capability.type === 'StrobeDuration',\n    create: (channel, capabilities) => {\n      const xmlDuration = xmlbuilder.create('duration');\n\n      for (const capability of getSingleUnitCapabilities(capabilities, 'duration', 's', 0, 2)) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue * 1000, capability.endValue * 1000);\n        xmlCapability.attribute('type', 'linear');\n        xmlDuration.importDocument(xmlCapability);\n      }\n\n      return xmlDuration;\n    },\n  },\n  pan: {\n    isCapSuitable: (capability) => capability.type === 'Pan',\n    create: (channel, capabilities) => {\n      const xmlPan = xmlbuilder.create('pan');\n\n      for (const capability of capabilities) {\n        xmlPan.element('range', {\n          range: capability.angle[1].number - capability.angle[0].number,\n        });\n      }\n\n      return xmlPan;\n    },\n  },\n  tilt: {\n    isCapSuitable: (capability) => ['Pan', 'Tilt'].includes(capability.type),\n    create: (channel, capabilities) => {\n      const xmlTilt = xmlbuilder.create('tilt');\n\n      for (const capability of capabilities) {\n        xmlTilt.element('range', {\n          range: capability.angle[1].number - capability.angle[0].number,\n        });\n      }\n\n      return xmlTilt;\n    },\n  },\n  panTiltSpeed: {\n    isCapSuitable: (capability) => capability.type === 'PanTiltSpeed',\n    create: (channel, capabilities) => {\n      const xmlPanTiltSpeed = xmlbuilder.create('ptspeed');\n\n      const speedCapabilities = getSingleUnitCapabilities(\n        capabilities.filter((capability) => capability.speed !== null), 'speed', '%',\n      );\n      const durationCapabilities = getSingleUnitCapabilities(\n        capabilities.filter((capability) => capability.duration !== null), 'duration', '%',\n      );\n\n      for (const capability of speedCapabilities) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlCapability.attribute('type', 'linear');\n        xmlPanTiltSpeed.importDocument(xmlCapability);\n      }\n\n      for (const capability of durationCapabilities) {\n        // 100% duration means low speed, so we need to invert this\n        const xmlCapability = getBaseXmlCapability(capability.capObject, 100 - capability.startValue, 100 - capability.endValue);\n        xmlCapability.attribute('type', 'linear');\n        xmlPanTiltSpeed.importDocument(xmlCapability);\n      }\n\n      return xmlPanTiltSpeed;\n    },\n  },\n  color: {\n    isCapSuitable: (capability) => capability.type === 'ColorIntensity' || (capability.type === 'NoFunction' && capability._channel.type === 'Single Color'),\n    create: (channel, capabilities) => {\n      const capabilitiesPerColor = {};\n\n      for (const capability of capabilities) {\n        let color = capability.color;\n        if (color === 'Warm White' || color === 'Cold White') {\n          color = 'White';\n        }\n\n        if (!(color in capabilitiesPerColor)) {\n          capabilitiesPerColor[color] = [];\n        }\n        capabilitiesPerColor[color].push(capability);\n      }\n\n      delete capabilitiesPerColor.null; // NoFunction caps will be ignored\n\n      return Object.keys(capabilitiesPerColor).map((color, index) => {\n        const colorCapabilities = capabilitiesPerColor[color];\n        const xmlColor = xmlbuilder.create(color.toLowerCase());\n\n        if (Object.keys(capabilitiesPerColor).length > 1) {\n          const dmxControlCapabilities = getSingleUnitCapabilities(colorCapabilities, 'brightness', '%');\n          for (const capability of dmxControlCapabilities) {\n            const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n            xmlCapability.attribute('type', 'linear');\n            xmlColor.importDocument(xmlCapability);\n          }\n        }\n\n        return xmlColor;\n      });\n    },\n  },\n  colorWheel: {\n    isCapSuitable: (capability) => capability.isSlotType('Color') || capability.type === 'ColorPreset' || (capability.type === 'WheelRotation' && capability.speed && capability.wheels.some((wheel) => wheel.type === 'Color')),\n    create: (channel, capabilities) => {\n      const xmlColorWheel = xmlbuilder.create('colorwheel');\n\n      // RGB value for dummy colors. Will be decremented by 1 every time a dummy color is created.\n      let greyValue = 0x99;\n\n      const presetCapabilities = capabilities.filter((capability) => capability.isSlotType('Color') || capability.type === 'ColorPreset');\n\n      // split proportional caps so we only have stepped caps\n      for (let index = 0; index < presetCapabilities.length; index++) {\n        const capability = presetCapabilities[index];\n\n        if (!capability.isStep) {\n          const splittedCapabilities = getSplittedCapabilities(capability);\n          presetCapabilities.splice(index, 1, ...splittedCapabilities);\n        }\n      }\n\n      // merge adjacent stepped caps\n      for (let index = 0; index < presetCapabilities.length; index++) {\n        const capability = presetCapabilities[index];\n\n        if (index + 1 < presetCapabilities.length) {\n          const nextCapability = presetCapabilities[index + 1];\n          const mergedCapability = getMergedCapability(capability, nextCapability);\n\n          if (mergedCapability) {\n            presetCapabilities.splice(index, 2, mergedCapability);\n            index--; // maybe the merged capability can be merged another time\n          }\n        }\n      }\n\n      for (const capability of presetCapabilities) {\n        xmlColorWheel.element('step', {\n          type: 'color',\n          val: getColor(capability),\n          mindmx: capability.getDmxRangeWithResolution(CoarseChannel.RESOLUTION_8BIT).start,\n          maxdmx: capability.getDmxRangeWithResolution(CoarseChannel.RESOLUTION_8BIT).end,\n          caption: capability.name,\n        });\n      }\n\n      const rotationCapabilities = getSingleUnitCapabilities(\n        capabilities.filter((capability) => capability.type === 'WheelRotation'), 'speed', 'Hz', 0, 15,\n      );\n      if (rotationCapabilities.length > 0) {\n        const xmlWheelRotation = xmlColorWheel.element('wheelrotation');\n        for (const capability of rotationCapabilities) {\n          xmlWheelRotation.importDocument(getRotationSpeedXmlCapability(capability));\n        }\n      }\n\n      return xmlColorWheel;\n\n      /**\n       * @param {Capability} capability A capability with different start/end values.\n       * @returns {Capability[]} One capability representing the start value and one representing the end value.\n       */\n      function getSplittedCapabilities(capability) {\n        const startCapabilityJson = {\n          dmxRange: [capability.rawDmxRange.start, capability.rawDmxRange.start],\n          _splitted: true,\n        };\n        const centerCapabilityJson = {\n          dmxRange: [capability.rawDmxRange.center, capability.rawDmxRange.center],\n          _splitted: true,\n        };\n        const endCapabilityJson = {\n          dmxRange: [capability.rawDmxRange.end, capability.rawDmxRange.end],\n          _splitted: true,\n        };\n\n        for (let [key, value] of Object.entries(capability.jsonObject)) {\n          if (key === 'dmxRange') {\n            continue;\n          }\n\n          if (key.includes('Start')) {\n            key = key.replace('Start', '');\n            startCapabilityJson[key] = value;\n          }\n          else if (key.includes('End')) {\n            key = key.replace('End', '');\n            endCapabilityJson[key] = value;\n          }\n          else {\n            startCapabilityJson[key] = value;\n            centerCapabilityJson[key] = value;\n            endCapabilityJson[key] = value;\n          }\n        }\n\n        if (capability.hasComment) {\n          const startEndRegex = /^([\\d a-z]+?) *(?:…|->?|\\bto\\b) *([\\d a-z]+?)$/i; // Red…Blue, Red to Blue, Red -> Blue, Red-Blue, ...\n          const match = startEndRegex.exec(capability.comment);\n\n          if (match) {\n            const [, startColorName, endColorName] = match;\n            startCapabilityJson.comment = startColorName.replace(/^[a-z]/, (firstLetter) => firstLetter.toUpperCase());\n            endCapabilityJson.comment = endColorName.replace(/^[a-z]/, (firstLetter) => firstLetter.toUpperCase());\n          }\n        }\n\n        if ('slotNumber' in startCapabilityJson) {\n          centerCapabilityJson.slotNumber = (capability.slotNumber[0].number + capability.slotNumber[1].number) / 2;\n        }\n        if ('colors' in startCapabilityJson) {\n          centerCapabilityJson.colors = capability.colors.allColors;\n        }\n\n        const [startCapability, centerCapability, endCapability] = [startCapabilityJson, centerCapabilityJson, endCapabilityJson].map(\n          (capabilityJson) => new Capability(capabilityJson, capability._resolution, capability._channel),\n        );\n\n        if (capability.slotNumber) {\n          return [startCapability, centerCapability, endCapability];\n        }\n        return [startCapability, endCapability];\n      }\n\n      /**\n       * @param {Capability} capability1 A capability.\n       * @param {Capability} capability2 Another capability.\n       * @returns {Capability|null} A capability that combines the values of both given capabilities. Null if merging was not possible.\n       */\n      function getMergedCapability(capability1, capability2) {\n        if (!capability1.rawDmxRange.isAdjacentTo(capability2.rawDmxRange)) {\n          return null;\n        }\n\n        const filterDistinguishableKeys = (key) => !['dmxRange', '_splitted', 'menuClick'].includes(key);\n        const distinguishableKeys1 = Object.keys(capability1.jsonObject).filter((key) => filterDistinguishableKeys(key));\n        const distinguishableKeys2 = Object.keys(capability2.jsonObject).filter((key) => filterDistinguishableKeys(key));\n        const hasDifferentKeys = !arraysEqual(distinguishableKeys1, distinguishableKeys2);\n        const hasDifferentValues = distinguishableKeys1.some((key) => {\n          const value1 = capability1.jsonObject[key];\n          const value2 = capability2.jsonObject[key];\n\n          if (key === 'slotNumber') {\n            // slotNumber 8 and slotNumber 1 are the same slots if the wheel only has 7 slots\n            return !arraysEqual(capability1.wheelSlot, capability2.wheelSlot);\n          }\n\n          return value1 !== value2 && !arraysEqual(value1, value2);\n        });\n        if (hasDifferentKeys || hasDifferentValues) {\n          return null;\n        }\n\n        const capabilityJson = {};\n        const preferredJsonObject = capability1.jsonObject._splitted ? capability2.jsonObject : capability1.jsonObject; // we prefer unsplitted capability\n        for (const [key, value] of Object.entries(preferredJsonObject)) {\n          capabilityJson[key] = value;\n        }\n\n        const dmxRange = capability1.rawDmxRange.getRangeMergedWith(capability2.rawDmxRange);\n        capabilityJson.dmxRange = [dmxRange.start, dmxRange.end];\n\n        return new Capability(capabilityJson, capability1._resolution, capability1._channel);\n      }\n\n      /**\n       * @param {Capability} capability A capability.\n       * @returns {string} A color from the given capability's color data if there's only one color. A generic (and probably unique) grey color instead.\n       */\n      function getColor(capability) {\n        if (capability.colors && capability.colors.allColors.length === 1) {\n          return capability.colors.allColors[0];\n        }\n\n        const hex = (greyValue--).toString(16);\n        return `#${hex}${hex}${hex}`;\n      }\n    },\n  },\n  colorTemperature: {\n    isCapSuitable: (capability) => capability.type === 'ColorTemperature',\n    create: (channel, capabilities) => {\n      const xmlColorTemporary = xmlbuilder.create('colortemp');\n\n      const zeroPercentValue = 8000 - ((8000 - 2500) / 2);\n      const dmxControlCapabilities = getSingleUnitCapabilities(capabilities, 'colorTemperature', 'K', zeroPercentValue, 8000);\n      for (const capability of dmxControlCapabilities) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlCapability.attribute('type', 'linear');\n        xmlColorTemporary.importDocument(xmlCapability);\n      }\n\n      return xmlColorTemporary;\n    },\n  },\n  goboWheel: {\n    isCapSuitable: (capability) => capability.isSlotType('Gobo') || (capability.type === 'WheelRotation' && capability.speed && capability.wheels.some((wheel) => wheel.type === 'Gobo')),\n    create: (channel, capabilities) => {\n      const xmlGoboWheel = xmlbuilder.create('gobowheel');\n\n      const capabilitiesPerSlot = {};\n\n      // search for first normal cap and first shaking cap per index\n      // further caps of the same index will be ignored (for now)\n      const slotCapabilities = capabilities.filter((capability) => capability.isSlotType('Gobo'));\n      for (const capability of slotCapabilities) {\n        const slotNumber = `${capability.slotNumber[0]}…${capability.slotNumber[1]}`;\n\n        if (!(slotNumber in capabilitiesPerSlot)) {\n          capabilitiesPerSlot[slotNumber] = {\n            normalCap: null,\n            shakingCap: null,\n          };\n        }\n\n        if (capability.type !== 'WheelShake' && !capabilitiesPerSlot[slotNumber].normalCap) {\n          capabilitiesPerSlot[slotNumber].normalCap = capability;\n        }\n        else if (capability.type === 'WheelShake' && !capabilitiesPerSlot[slotNumber].shakingCap) {\n          capabilitiesPerSlot[slotNumber].shakingCap = capability;\n        }\n      }\n\n      const usesShake = Object.values(capabilitiesPerSlot).some(({ shakingCap }) => shakingCap !== null);\n      if (usesShake) {\n        xmlGoboWheel.element('goboshake');\n      }\n\n      for (const { normalCap, shakingCap } of Object.values(capabilitiesPerSlot)) {\n        if (normalCap) {\n          const xmlCapability = getBaseXmlCapability(normalCap);\n          xmlCapability.attribute('type', normalCap.isSlotType('Open') ? 'open' : 'gobo');\n          xmlCapability.attribute('caption', normalCap.name);\n\n          if (shakingCap) {\n            let xmlShakeCapability;\n\n            if (shakingCap.shakeSpeed) {\n              const [dmxControlCapability] = getSingleUnitCapabilities([shakingCap], 'shakeSpeed', 'Hz', 0, 20);\n              xmlShakeCapability = getBaseXmlCapability(shakingCap, dmxControlCapability.startValue, dmxControlCapability.endValue);\n            }\n            else {\n              xmlShakeCapability = getBaseXmlCapability(shakingCap);\n            }\n\n            xmlShakeCapability.attribute('handler', 'goboshake');\n            xmlCapability.importDocument(xmlShakeCapability);\n          }\n\n          xmlGoboWheel.importDocument(xmlCapability);\n        }\n      }\n\n      const rotationCapabilities = getSingleUnitCapabilities(\n        capabilities.filter((capability) => capability.type === 'WheelRotation'), 'speed', 'Hz', 0, 15,\n      );\n      if (rotationCapabilities.length > 0) {\n        const xmlWheelRotation = xmlGoboWheel.element('wheelrotation');\n        for (const capability of rotationCapabilities) {\n          xmlWheelRotation.importDocument(getRotationSpeedXmlCapability(capability));\n        }\n      }\n\n      return xmlGoboWheel;\n    },\n  },\n  goboIndex: { // gobo stencil rotation angle\n    isCapSuitable: (capability) => capability.type === 'WheelSlotRotation' && capability.wheels.some((wheel) => wheel.type === 'Gobo') && capability.angle !== null,\n    create: (channel, capabilities) => {\n      const xmlGoboIndex = xmlbuilder.create('goboindex');\n\n      for (const capability of getSingleUnitCapabilities(capabilities, 'angle', 'deg', 0, 360)) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlCapability.attribute('range', Math.abs(capability.endValue - capability.startValue));\n        xmlGoboIndex.importDocument(xmlCapability);\n      }\n\n      return xmlGoboIndex;\n    },\n  },\n  goboRotation: { // gobo stencil rotation speed\n    isCapSuitable: (capability) => capability.type === 'WheelSlotRotation' && capability.wheels.some((wheel) => wheel.type === 'Gobo') && capability.speed !== null,\n    create: (channel, capabilities) => {\n      const xmlGoboRotation = xmlbuilder.create('goborotation');\n\n      for (const capability of getSingleUnitCapabilities(capabilities, 'speed', 'Hz', 0, 5)) {\n        const xmlCapability = getRotationSpeedXmlCapability(capability);\n        xmlGoboRotation.importDocument(xmlCapability);\n      }\n\n      return xmlGoboRotation;\n    },\n  },\n  goboShake: { // gobo shake speed\n    isCapSuitable: (capability) => capability.type === 'WheelShake' && capability.wheels.some((wheel) => wheel.type === 'Gobo') && capability.wheelSlot === null && capability.shakeSpeed !== null,\n    create: (channel, capabilities) => {\n      const xmlGoboShake = xmlbuilder.create('goboshake');\n\n      for (const capability of getSingleUnitCapabilities(capabilities, 'shakeSpeed', 'Hz', 0, 20)) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlGoboShake.importDocument(xmlCapability);\n      }\n\n      return xmlGoboShake;\n    },\n  },\n  focus: {\n    isCapSuitable: (capability) => capability.type === 'Focus',\n    create: (channel, capabilities) => {\n      const xmlFocus = xmlbuilder.create('focus');\n\n      const dmxControlCapabilities = getSingleUnitCapabilities(capabilities, 'distance', '%');\n      for (const capability of dmxControlCapabilities) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlCapability.attribute('type', 'linear');\n        xmlFocus.importDocument(xmlCapability);\n      }\n\n      return xmlFocus;\n    },\n  },\n  frost: {\n    isCapSuitable: (capability) => capability.type === 'Frost',\n    create: (channel, capabilities) => {\n      const xmlFrost = xmlbuilder.create('frost');\n\n      if (capabilities.length > 1) {\n        for (const capability of capabilities) {\n          let xmlCapability;\n\n          if (capability.frostIntensity[0].number === capability.frostIntensity[1].number) {\n            // generate <step>s with value=\"true\" or value=\"false\"\n            // this is not documented, but used in other fixtures\n            const isFrostOn = capability.frostIntensity[0].number > 0;\n            xmlCapability = getBaseXmlCapability(capability);\n            xmlCapability.attribute('value', `${isFrostOn}`);\n          }\n          else {\n            xmlCapability = getBaseXmlCapability(capability, capability.frostIntensity[0].number, capability.frostIntensity[1].number);\n            xmlCapability.attribute('type', 'frost');\n          }\n\n          xmlFrost.importDocument(xmlCapability);\n        }\n      }\n\n      return xmlFrost;\n    },\n  },\n  iris: {\n    isCapSuitable: (capability) => capability.type === 'Iris',\n    create: (channel, capabilities) => {\n      const xmlIris = xmlbuilder.create('iris');\n\n      const dmxControlCapabilities = getSingleUnitCapabilities(capabilities, 'openPercent', '%');\n      for (const capability of dmxControlCapabilities) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlCapability.attribute('type', 'linear');\n        xmlIris.importDocument(xmlCapability);\n      }\n\n      return xmlIris;\n    },\n  },\n  zoom: {\n    isCapSuitable: (capability) => capability.type === 'Zoom',\n    create: (channel, capabilities) => {\n      const xmlZoom = xmlbuilder.create('zoom');\n\n      const dmxControlCapabilities = getSingleUnitCapabilities(capabilities, 'angle', 'deg', 0, 90);\n      for (const capability of dmxControlCapabilities) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlCapability.attribute('type', 'linear');\n        xmlZoom.importDocument(xmlCapability);\n      }\n\n      return xmlZoom;\n    },\n  },\n  prism: {\n    isCapSuitable: (capability) => capability.type === 'Prism' || (capability.type === 'NoFunction' && capability._channel.type === 'Prism'),\n    create: (channel, capabilities) => {\n      const xmlPrism = xmlbuilder.create('prism');\n\n      const hasRotationAngleCapabilities = capabilities.some((capability) => capability.angle !== null);\n      const hasRotationSpeedCapabilities = capabilities.some((capability) => capability.speed !== null);\n\n      if (hasRotationAngleCapabilities) {\n        xmlPrism.element('prismindex');\n      }\n\n      if (hasRotationSpeedCapabilities) {\n        xmlPrism.element('prismrotation');\n      }\n\n      // group adjacent capabilities by comment\n      const capabilitiesGroupedByComment = [];\n      for (const capability of capabilities) {\n        const lastGroup = capabilitiesGroupedByComment.at(-1);\n\n        if (lastGroup && lastGroup[0].type === capability.type && lastGroup[0].comment === capability.comment) {\n          // push to last group\n          lastGroup.push(capability);\n        }\n        else {\n          // push new group\n          capabilitiesGroupedByComment.push([capability]);\n        }\n      }\n\n      for (const commentGroup of capabilitiesGroupedByComment) {\n        const firstCapability = commentGroup[0];\n        const lastCapability = commentGroup.at(-1);\n\n        const xmlStep = xmlPrism.element('step', {\n          type: firstCapability.type === 'NoFunction' ? 'open' : 'prism',\n          mindmx: firstCapability.getDmxRangeWithResolution(CoarseChannel.RESOLUTION_8BIT).start,\n          maxdmx: lastCapability.getDmxRangeWithResolution(CoarseChannel.RESOLUTION_8BIT).end,\n          caption: firstCapability.name,\n        });\n\n        // add ranges for capabilities without rotation speed\n        const rotationAngleCapabilities = commentGroup.filter((capability) => capability.angle !== null);\n        for (const capability of rotationAngleCapabilities) {\n          const xmlRange = getBaseXmlCapability(capability, capability.angle[0].number, capability.angle[1].number);\n          xmlRange.attribute('range', capability.angle[1].number - capability.angle[0].number);\n          xmlRange.attribute('handler', 'prismindex');\n          xmlStep.importDocument(xmlRange);\n        }\n\n        // add ranges/steps for rotation speed dmx control capabilities\n        const rotationSpeedCapabilities = commentGroup.filter((capability) => capability.speed !== null);\n        for (const capability of getSingleUnitCapabilities(rotationSpeedCapabilities, 'speed', 'Hz', 0, 5)) {\n          const xmlCapability = getRotationSpeedXmlCapability(capability);\n          xmlCapability.attribute('handler', 'prismrotation');\n          xmlStep.importDocument(xmlCapability);\n        }\n      }\n\n      return xmlPrism;\n    },\n  },\n  prismIndex: { // rotation angle\n    isCapSuitable: (capability) => capability.type === 'PrismRotation' && capability.angle !== null,\n    create: (channel, capabilities) => {\n      const xmlPrismIndex = xmlbuilder.create('prismindex');\n\n      for (const capability of getSingleUnitCapabilities(capabilities, 'angle', 'deg', 0, 360)) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlCapability.attribute('range', Math.abs(capability.endValue - capability.startValue));\n        xmlPrismIndex.importDocument(xmlCapability);\n      }\n\n      return xmlPrismIndex;\n    },\n  },\n  prismRotation: { // rotation speed\n    isCapSuitable: (capability) => capability.type === 'PrismRotation' && capability.speed !== null,\n    create: (channel, capabilities) => {\n      const xmlPrismRotation = xmlbuilder.create('prismrotation');\n\n      for (const capability of getSingleUnitCapabilities(capabilities, 'speed', 'Hz', 0, 5)) {\n        const xmlCapability = getRotationSpeedXmlCapability(capability);\n        xmlPrismRotation.importDocument(xmlCapability);\n      }\n\n      return xmlPrismRotation;\n    },\n  },\n  fog: {\n    isCapSuitable: (capability) => capability.type === 'Fog' || (capability.type === 'NoFunction' && capability._channel.type === 'Fog'),\n    create: (channel, capabilities) => {\n      const xmlFog = xmlbuilder.create('fog');\n\n      if (capabilities.length > 1) {\n        for (const capability of capabilities) {\n          let xmlCapability;\n\n          if (capability.fogOutput !== null && capability.fogOutput[0].number !== capability.fogOutput[1].number) {\n            xmlCapability = getBaseXmlCapability(capability, capability.fogOutput[0].number, capability.fogOutput[1].number);\n            xmlCapability.attribute('type', 'fog');\n          }\n          else {\n            // generate <step>s with value=\"true\" or value=\"false\"\n            // this is not documented, but used in other fixtures\n            const isFogOn = capability.type !== 'NoFunction' && (capability.fogOutput === null || capability.fogOutput[0].number > 0);\n            xmlCapability = getBaseXmlCapability(capability);\n            xmlCapability.attribute('value', `${isFogOn}`);\n          }\n\n          xmlFog.importDocument(xmlCapability);\n        }\n      }\n\n      return xmlFog;\n    },\n  },\n  fan: {\n    isCapSuitable: (capability) => (capability.speed !== null || capability.type === 'NoFunction') && /\\bfan\\b/i.test(capability._channel.name),\n    create: (channel, capabilities) => {\n      const xmlFan = xmlbuilder.create('fan');\n\n      if (capabilities.length > 1) {\n        for (const capability of capabilities) {\n          let xmlCapability;\n\n          if (capability.speed !== null && capability.speed[0].number !== capability.speed[1].number) {\n            xmlCapability = getBaseXmlCapability(capability, Math.abs(capability.speed[0].number), Math.abs(capability.speed[1].number));\n            xmlCapability.attribute('type', 'fan');\n          }\n          else {\n            // generate <step>s with value=\"true\" or value=\"false\"\n            // this is not documented, but used in other fixtures\n            const isFanOn = capability.type !== 'NoFunction' && (capability.speed[0].number > 0);\n            xmlCapability = getBaseXmlCapability(capability);\n            xmlCapability.attribute('value', `${isFanOn}`);\n          }\n\n          xmlFan.importDocument(xmlCapability);\n        }\n      }\n\n      return xmlFan;\n    },\n  },\n  index: { // rotation angle\n    isCapSuitable: (capability) => capability.angle && capability.type.includes('Rotation'),\n    create: (channel, capabilities) => {\n      const xmlIndex = xmlbuilder.create('index');\n\n      for (const capability of getSingleUnitCapabilities(capabilities, 'angle', 'deg', 0, 360)) {\n        const xmlCapability = getBaseXmlCapability(capability.capObject, capability.startValue, capability.endValue);\n        xmlCapability.attribute('range', Math.abs(capability.endValue - capability.startValue));\n        xmlIndex.importDocument(xmlCapability);\n      }\n\n      return xmlIndex;\n    },\n  },\n  rotation: { // rotation speed\n    isCapSuitable: (capability) => capability.speed !== null && capability.type.match(/(Rotation|Continuous)/),\n    create: (channel, capabilities) => {\n      const xmlRotation = xmlbuilder.create('rotation');\n\n      const dmxControlCapabilities = getSingleUnitCapabilities(capabilities, 'speed', 'Hz', 0, 5);\n      for (const capability of dmxControlCapabilities) {\n        xmlRotation.importDocument(getRotationSpeedXmlCapability(capability));\n      }\n\n      return xmlRotation;\n    },\n  },\n  rawStep: { // only steps\n    isCapSuitable: (capability) => capability._channel.type !== 'NoFunction' && (capability._channel.capabilities.every((capability_) => capability_.isStep) || capability.usedStartEndEntities.length === 0),\n    create: (channel, capabilities) => {\n      const xmlRawStep = xmlbuilder.create('rawstep');\n\n      for (const capability of capabilities) {\n        const xmlCapability = getBaseXmlCapability(capability);\n        xmlCapability.attribute('caption', capability.name);\n        xmlRawStep.importDocument(xmlCapability);\n      }\n\n      return xmlRawStep;\n    },\n  },\n  raw: { // steps and ranges\n    isCapSuitable: (capability) => capability._channel.type !== 'NoFunction' && capability.usedStartEndEntities.length > 0,\n    create: (channel, capabilities) => {\n      const xmlRaw = xmlbuilder.create('raw');\n\n      for (const capability of capabilities) {\n        const [startEntity, endEntity] = capability[capability.usedStartEndEntities[0]];\n        const xmlCapability = getBaseXmlCapability(capability, startEntity.number, endEntity.number);\n        xmlCapability.attribute('caption', capability.name);\n        xmlCapability.attribute('type', capability.usedStartEndEntities[0] === 'speed' && startEntity.number === endEntity.number ? 'stop' : 'linear');\n        xmlRaw.importDocument(xmlCapability);\n      }\n\n      return xmlRaw;\n    },\n  },\n};\n\n/**\n * @typedef {object} DmxControlCapability\n * @property {Capability} capObject The OFL capability object.\n * @property {number} startValue The capability's start value in the allowed unit.\n * @property {number} endValue The capability's end value in the allowed unit.\n */\n\n/**\n * Converts all property values to the allowed unit.\n * @param {Capability[]} capabilities Array of capabilities that use the given property.\n * @param {string} property Name of the property whose values should be normalized.\n * @param {string} allowedUnit The unit all capabilities should be converted to. Must be a base unit (i. e. no `ms` but `s`) or `%`.\n * @param {number} zeroPercentValue The equivalent of 0% in the allowed unit. Must be used if allowedUnit is not percent.\n * @param {number} hundredPercentValue The equivalent of 100% in the allowed unit. Must be used if allowedUnit is not percent.\n * @returns {DmxControlCapability[]} Array of objects wrapping the original capabilities.\n */\nfunction getSingleUnitCapabilities(capabilities, property, allowedUnit, zeroPercentValue, hundredPercentValue) {\n  const dmxControlCapabilities = capabilities.map((capability) => {\n    const startEntity = capability[property][0].baseUnitEntity;\n    const endEntity = capability[property][1].baseUnitEntity;\n\n    return {\n      capObject: capability,\n      unit: startEntity.unit,\n      startValue: startEntity.number,\n      endValue: endEntity.number,\n    };\n  });\n\n  // they should all be of the same (wrong) unit, as we converted to the base unit above\n  const capabilitiesWithWrongUnit = dmxControlCapabilities.filter((capability) => capability.unit !== allowedUnit);\n  const maxValueWithWrongUnit = Math.max(...(capabilitiesWithWrongUnit.map((capability) => Math.max(Math.abs(capability.startValue), Math.abs(capability.endValue)))));\n  if (allowedUnit !== '%') {\n    // we take the conversion from percent to unit as a linear function f(x) = (m*x + t)\n    // where x is the percentage value and f(x) or y is the value in the allowed unit\n    const m = (hundredPercentValue - zeroPercentValue) / 100; // delta y / delta x\n    const t = zeroPercentValue; // f(0) = m * 0 + t = t\n    const percentToUnit = (x) => (m * x) + t;\n\n    for (const capability of capabilitiesWithWrongUnit) {\n      capability.unit = allowedUnit;\n      capability.startValue = percentToUnit(capability.startValue);\n      capability.endValue = percentToUnit(capability.endValue);\n    }\n  }\n  else if (maxValueWithWrongUnit !== 0) {\n    for (const capability of capabilitiesWithWrongUnit) {\n      capability.unit = allowedUnit;\n      capability.startValue = capability.startValue / maxValueWithWrongUnit * 100;\n      capability.endValue = capability.endValue / maxValueWithWrongUnit * 100;\n    }\n  }\n\n  for (const capability of dmxControlCapabilities) {\n    delete capability.unit;\n  }\n\n  return dmxControlCapabilities;\n}\n\n/**\n * This function already handles swapping DMX start/end if the given start/end value is inverted (i.e. decreasing).\n * @param {Capability} capability The capability to use as data source.\n * @param {number|null} startValue The start value of an start/end entity, e.g. speedStart. Unit can be freely chosen. Omit if minval/maxval should not be added.\n * @param {number|null} endValue The end value of an start/end entity, e.g. speedEnd. Unit can be freely chosen. Omit if minval/maxval should not be added.\n * @returns {XMLElement} A <step> or <range> with mindmx, maxdmx and, optionally, minval and maxval attributes.\n */\nfunction getBaseXmlCapability(capability, startValue = null, endValue = null) {\n  const dmxRange = capability.getDmxRangeWithResolution(CoarseChannel.RESOLUTION_8BIT);\n  let [dmxStart, dmxEnd] = [dmxRange.start, dmxRange.end];\n\n  if (startValue !== null && startValue > endValue) {\n    [startValue, endValue] = [endValue, startValue];\n    [dmxStart, dmxEnd] = [dmxEnd, dmxStart];\n  }\n\n  const xmlCapability = xmlbuilder.create(capability.isStep ? 'step' : 'range');\n  xmlCapability.attribute('mindmx', dmxStart);\n  xmlCapability.attribute('maxdmx', dmxEnd);\n\n  if (startValue !== null) {\n    if (startValue === endValue) {\n      xmlCapability.attribute('val', Number.parseFloat(startValue.toFixed(3)));\n    }\n    else {\n      xmlCapability.attribute('minval', Number.parseFloat(startValue.toFixed(3)));\n      xmlCapability.attribute('maxval', Number.parseFloat(endValue.toFixed(3)));\n    }\n  }\n\n  return xmlCapability;\n}\n\n/**\n * @param {DmxControlCapability} capability The DMX control capability; i.e. speed is in Hz.\n * @returns {XMLElement} A capability xml element with the proper stop/cw/ccw type\n */\nfunction getRotationSpeedXmlCapability(capability) {\n  if (capability.startValue === 0 && capability.endValue === 0) {\n    const xmlStep = getBaseXmlCapability(capability.capObject);\n    xmlStep.attribute('type', 'stop');\n    return xmlStep;\n  }\n\n  const xmlRange = getBaseXmlCapability(capability.capObject, Math.abs(capability.startValue), Math.abs(capability.endValue));\n  xmlRange.attribute('type', (capability.startValue >= 0 && capability.endValue >= 0) ? 'cw' : 'ccw');\n  return xmlRange;\n}\n\n/**\n * @param {Array} array1 First array to compare.\n * @param {Array} array2 Second array to compare.\n * @returns {boolean} Whether both arrays have equal size and their items do strictly equal.\n */\nfunction arraysEqual(array1, array2) {\n  if (array1 === array2) {\n    return true;\n  }\n\n  if (!Array.isArray(array1) || !Array.isArray(array2)) {\n    return false;\n  }\n\n  return array1.length === array2.length && array1.every(\n    (item, index) => item === array2[index],\n  );\n}\n"
  },
  {
    "path": "plugins/dmxcontrol3/export.js",
    "content": "import sanitize from 'sanitize-filename';\nimport xmlbuilder from 'xmlbuilder';\nimport FineChannel from '../../lib/model/FineChannel.js';\nimport NullChannel from '../../lib/model/NullChannel.js';\nimport SwitchingChannel from '../../lib/model/SwitchingChannel.js';\nimport ddf3FunctionGroups from './ddf3-function-groups.js';\nimport ddf3Functions from './ddf3-functions.js';\n\nexport const version = '0.1.2';\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const deviceDefinitions = [];\n\n  for (const fixture of fixtures) {\n    // add device for each mode\n    for (const mode of fixture.modes) {\n      try {\n        deviceDefinitions.push(exportFixtureMode(fixture, mode, options));\n      }\n      catch (error) {\n        throw new Error(`Exporting fixture mode ${fixture.manufacturer.key}/${fixture.key}/${mode.shortName} failed: ${error}`, {\n          cause: error,\n        });\n      }\n    }\n  }\n\n  return deviceDefinitions;\n}\n\n/**\n * @param {Fixture} fixture The fixture to export.\n * @param {Mode} mode The mode to export.\n * @param {object} options Global options.\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {object} The generated file.\n */\nfunction exportFixtureMode(fixture, mode, options) {\n  const xml = xmlbuilder.begin()\n    .declaration('1.0', 'utf-8')\n    .element({\n      device: {\n        '@type': 'DMXDevice',\n        '@dmxaddresscount': mode.channelKeys.length,\n        '@dmxcversion': 3,\n        '@ddfversion': options.displayedPluginVersion ?? version,\n      },\n    });\n\n  addInformation(xml, mode);\n  addFunctions(xml, mode);\n  addProcedures(xml, mode);\n\n  return {\n    name: sanitize(`${fixture.manufacturer.key}-${fixture.key}-${(mode.shortName)}.xml`).replaceAll(/\\s+/g, '-'),\n    content: xml.end({\n      pretty: true,\n      indent: '  ',\n    }),\n    mimetype: 'application/xml',\n    fixtures: [fixture],\n    mode: mode.shortName,\n  };\n}\n\n/**\n * Adds the information block to the specified XML file.\n * @param {XMLDocument} xml The device definition to add the information to\n * @param {Mode} mode The definition's mode\n */\nfunction addInformation(xml, mode) {\n  const xmlInfo = xml.element('information');\n  xmlInfo.element('model').text(mode.fixture.name);\n  xmlInfo.element('vendor').text(mode.fixture.manufacturer.name);\n  xmlInfo.element('author').text(mode.fixture.meta.authors.join(', '));\n  xmlInfo.element('mode').text(mode.name);\n\n  if (mode.fixture.hasComment) {\n    xmlInfo.element('comment').text(mode.fixture.comment);\n  }\n}\n\n/**\n * @typedef {Map<string | null, CoarseChannel[]>} ChannelsPerPixel\n */\n\n/**\n * @typedef {Map<string | null, XMLElement[]>} XmlFunctionsPerPixel\n */\n\n/**\n * Adds the DMX channels as functions to the specified XML file.\n * @param {XMLDocument} xml The device definition to add the functions to.\n * @param {Mode} mode The definition's mode.\n */\nfunction addFunctions(xml, mode) {\n  const channelsPerPixel = getChannelsPerPixel(mode);\n  /** @type {XmlFunctionsPerPixel} */\n  const xmlFunctionsPerPixel = new Map();\n\n  for (const [pixelKey, pixelChannels] of channelsPerPixel) {\n    const xmlChannelFunctions = [];\n    for (const channel of pixelChannels) {\n      xmlChannelFunctions.push(...getXmlFunctionsFromChannel(channel));\n    }\n\n    groupXmlFunctions(xmlChannelFunctions);\n    xmlFunctionsPerPixel.set(pixelKey, xmlChannelFunctions);\n  }\n\n  addMatrix(mode, xmlFunctionsPerPixel);\n\n  for (const [pixelKey, xmlFunctions] of xmlFunctionsPerPixel) {\n    if (xmlFunctions.length > 0) {\n      const xmlFunctionsContainer = xml.element('functions');\n\n      if (pixelKey !== null) {\n        xmlFunctionsContainer.comment(pixelKey);\n      }\n\n      for (const xmlFunction of xmlFunctions) {\n        xmlFunctionsContainer.importDocument(xmlFunction);\n      }\n    }\n  }\n\n  /**\n   * @param {CoarseChannel} channel The channel that should be represented as one or more DMXControl functions.\n   * @returns {XMLElement[]} Functions created by this channel. They are not automatically grouped together.\n   */\n  function getXmlFunctionsFromChannel(channel) {\n    const functionToCapabilities = {};\n\n    for (const capability of channel.capabilities) {\n      const properFunction = Object.keys(ddf3Functions).find(\n        (key) => ddf3Functions[key].isCapSuitable(capability),\n      );\n\n      if (properFunction) {\n        if (!Object.keys(functionToCapabilities).includes(properFunction)) {\n          functionToCapabilities[properFunction] = [];\n        }\n        functionToCapabilities[properFunction].push(capability);\n      }\n    }\n\n    const xmlFunctions = [];\n    for (const functionKey of Object.keys(functionToCapabilities)) {\n      const capabilities = functionToCapabilities[functionKey];\n      const functions = ddf3Functions[functionKey].create(channel, capabilities);\n      if (Array.isArray(functions)) {\n        xmlFunctions.push(...functions);\n      }\n      else {\n        xmlFunctions.push(functions);\n      }\n    }\n    for (const xmlFunction of xmlFunctions) {\n      addChannelAttributes(xmlFunction, mode, channel);\n    }\n\n    return xmlFunctions;\n  }\n\n  /**\n   * Merges and renames the given XML functions. Modifies the array.\n   * @param {XMLElement[]} xmlFunctions Channel-level XML functions.\n   */\n  function groupXmlFunctions(xmlFunctions) {\n    for (const group of ddf3FunctionGroups) {\n      const foundFunctions = {};\n      for (const functionName of group.functions) {\n        foundFunctions[functionName] = [];\n      }\n\n      for (const xmlFunction of xmlFunctions) {\n        if (xmlFunction.name in foundFunctions) {\n          foundFunctions[xmlFunction.name].push(xmlFunction);\n        }\n      }\n\n      const completeGroups = Math.min(...Object.values(foundFunctions).map((items) => items.length));\n      for (let index = 0; index < completeGroups; index++) {\n        // take i-th function from each function type\n        const groupFunctions = Object.values(foundFunctions).map((items) => items[index]);\n        const xmlGroup = group.getXmlGroup(...groupFunctions);\n\n        // insert xml group at the position of the first grouped function\n        xmlFunctions.splice(xmlFunctions.indexOf(groupFunctions[0]), 0, xmlGroup);\n\n        // remove grouped functions from list\n        for (const function_ of groupFunctions) {\n          xmlFunctions.splice(xmlFunctions.indexOf(function_), 1);\n        }\n      }\n    }\n  }\n}\n\n/**\n * @param {Mode} mode The definition's mode.\n * @returns {ChannelsPerPixel} Each pixel key pointing to its unwrapped matrix channels. null points to all non-matrix channels.\n */\nfunction getChannelsPerPixel(mode) {\n  const channelsPerPixel = new Map([[null, []]]);\n\n  const matrix = mode.fixture.matrix;\n  if (matrix !== null) {\n    const pixelKeys = [...matrix.pixelGroupKeys, ...matrix.getPixelKeysByOrder('X', 'Y', 'Z')];\n    for (const key of pixelKeys) {\n      channelsPerPixel.set(key, []);\n    }\n  }\n\n  const channels = mode.channels.map(\n    (channel) => (channel instanceof SwitchingChannel ? channel.defaultChannel : channel),\n  ).filter(\n    (channel) => !(channel instanceof FineChannel || channel instanceof NullChannel),\n  );\n  for (const channel of channels) {\n    channelsPerPixel.get(channel.pixelKey).push(channel);\n  }\n\n  return channelsPerPixel;\n}\n\n/**\n * Adds the Maintenance capabilities as procedures to the specified XML file.\n * @param {XMLDocument} xml The device definition to add the functions to.\n * @param {Mode} mode The definition's mode.\n */\nfunction addProcedures(xml, mode) {\n  const maintenanceCapabilities = [];\n\n  for (let channel of mode.channels) {\n    if (channel instanceof SwitchingChannel) {\n      channel = channel.defaultChannel;\n    }\n\n    if (channel instanceof FineChannel) {\n      continue;\n    }\n\n    maintenanceCapabilities.push(...channel.capabilities.filter(\n      (capability) => capability.type === 'Maintenance' && capability.isStep,\n    ));\n  }\n\n  if (maintenanceCapabilities.length === 0) {\n    return;\n  }\n\n  const xmlProcedures = xml.element('procedures');\n\n  for (const capability of maintenanceCapabilities) {\n    const channelIndex = mode.getChannelIndex(capability._channel.key);\n\n    const xmlProcedure = xmlProcedures.element('procedure', {\n      name: capability.comment,\n    });\n\n    xmlProcedure.element('set', {\n      dmxchannel: channelIndex,\n      value: capability.dmxRange.start,\n    });\n\n    if (capability.hold) {\n      xmlProcedure.element('hold', {\n        value: capability.hold.baseUnitEntity.number * 1000,\n      });\n\n      xmlProcedure.element('restore', {\n        dmxchannel: channelIndex,\n      });\n    }\n  }\n}\n\n/**\n * Combines several XML functions from the individual pixels to a single <matrix> function, if possible.\n * @param {Mode} mode The definition's mode.\n * @param {XmlFunctionsPerPixel} xmlFunctionsPerPixel Pixel keys pointing to its xml functions.\n */\nfunction addMatrix(mode, xmlFunctionsPerPixel) {\n  const matrix = mode.fixture.matrix;\n  const hasSuitableCategory = mode.fixture.categories.includes('Matrix') || mode.fixture.categories.includes('Pixel Bar');\n\n  if (matrix === null || !hasSuitableCategory) {\n    return;\n  }\n\n  const pixelKeys = matrix.getPixelKeysByOrder('X', 'Y', 'Z');\n\n  const isMonochromeMatrix = pixelKeys.every((pixelKey) => {\n    const xmlFunctions = xmlFunctionsPerPixel.get(pixelKey);\n    return xmlFunctions.length === 1 && xmlFunctions[0].name === 'dimmer';\n  });\n\n  const isRgbMatrix = pixelKeys.every((pixelKey) => {\n    const xmlFunctions = xmlFunctionsPerPixel.get(pixelKey);\n    return xmlFunctions.length === 1 && xmlFunctions[0].name === 'rgb';\n  });\n\n  if (!isMonochromeMatrix && !isRgbMatrix) {\n    return;\n  }\n\n  const xmlMatrix = xmlbuilder.create('matrix');\n  xmlMatrix.attribute('rows', matrix.pixelCountY);\n  xmlMatrix.attribute('columns', matrix.pixelCountX);\n\n  for (const pixelKey of pixelKeys) {\n    xmlMatrix.importDocument(xmlFunctionsPerPixel.get(pixelKey).shift());\n  }\n\n  xmlFunctionsPerPixel.get(null).push(xmlMatrix);\n}\n\n/**\n * Adds name attribute, dmxchannel attribute and attributes for fine channels (if used in mode) to the given channel function.\n * @param {XMLElement} xmlElement The XML element to which the attributes should be added.\n * @param {Mode} mode The definition's mode.\n * @param {CoarseChannel} channel The channel whose data is used.\n */\nfunction addChannelAttributes(xmlElement, mode, channel) {\n  xmlElement.attribute('name', channel.name);\n\n  const index = mode.getChannelIndex(channel.key);\n  xmlElement.attribute('dmxchannel', index);\n\n  const fineIndices = channel.fineChannels.map(\n    (fineChannel) => mode.getChannelIndex(fineChannel.key),\n  );\n\n  if (fineIndices.length > 0 && fineIndices[0] !== -1) {\n    xmlElement.attribute('finedmxchannel', fineIndices[0]);\n\n    if (fineIndices.length > 1 && fineIndices[1] !== -1) {\n      xmlElement.attribute('ultradmxchannel', fineIndices[1]);\n\n      if (fineIndices.length > 2 && fineIndices[2] !== -1) {\n        xmlElement.attribute('ultrafinedmxchannel', fineIndices[2]);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/dmxcontrol3/exportTests/channel-numbers.js",
    "content": "import { promisify } from 'util';\nimport xml2js from 'xml2js';\nimport Range from '../../../lib/model/Range.js';\nimport SwitchingChannel from '../../../lib/model/SwitchingChannel.js';\n\n/**\n * @param {object} exportFile The file returned by the plugins' export module.\n * @param {string} exportFile.name File name, may include slashes to provide a folder structure.\n * @param {string} exportFile.content File content.\n * @param {string} exportFile.mimetype File mime type.\n * @param {Fixture[]} exportFile.fixtures Fixture objects that are described in given file; may be omitted if the file doesn't belong to any fixture (e.g. manufacturer information).\n * @param {string} exportFile.mode Mode's shortName if given file only describes a single mode.\n * @returns {Promise} Resolve when the test passes or reject with an error or an array of errors if the test fails.\n */\nexport default async function testChannelNumbers(exportFile) {\n  const parser = new xml2js.Parser();\n  const parseString = promisify(parser.parseString);\n\n  const fixture = exportFile.fixtures[0];\n  const exportMode = fixture.modes.find((mode) => mode.shortName === exportFile.mode);\n  const channelCount = exportMode.channels.length;\n\n  /** @type {Record<number, Range[]>} */\n  const usedChannelRanges = {};\n\n  const errors = [];\n\n  const xml = await parseString(exportFile.content);\n  const xmlFunctions = xml.device.functions.filter(\n    // filter out tags without content\n    (xmlFunction) => typeof xmlFunction === 'object',\n  );\n  for (const xmlFunction of xmlFunctions) {\n    findChannels(xmlFunction, -1);\n  }\n\n  checkUsedChannels();\n\n  if (errors.length > 0) {\n    throw errors;\n  }\n\n  /**\n   * Recursively searches the given XML tree for tags with dmxchannel attributes and capabilities.\n   * @param {XMLElement} xmlNode A single XML node.\n   * @param {number} currentChannelIndex The index of the channel if the xmlNode is inside a function associated to a channel. Else, it's -1.\n   */\n  function findChannels(xmlNode, currentChannelIndex) {\n    if (xmlNode.$) {\n      const indexAttributes = [\n        'dmxchannel',\n        'finedmxchannel',\n        'ultradmxchannel',\n        'ultrafinedmxchannel',\n      ].filter((attribute) => attribute in xmlNode.$);\n      for (const attribute of indexAttributes) {\n        const channelIndex = Number.parseInt(xmlNode.$[attribute], 10);\n\n        if (!(channelIndex in usedChannelRanges)) {\n          usedChannelRanges[channelIndex] = [];\n        }\n\n        if (attribute === 'dmxchannel') {\n          currentChannelIndex = channelIndex;\n        }\n\n        if (channelIndex >= channelCount) {\n          errors.push(`${attribute}=${channelIndex} is out of range (maximum: ${channelCount - 1}).`);\n        }\n      }\n\n      if ('mindmx' in xmlNode.$) {\n        // xmlNode is a capability\n        addCapability(xmlNode, currentChannelIndex);\n      }\n    }\n\n    for (const tagname of Object.keys(xmlNode)) {\n      if (tagname !== '$') {\n        for (const child of xmlNode[tagname]) {\n          findChannels(child, currentChannelIndex);\n        }\n      }\n    }\n  }\n\n  /**\n   * Checks the given capability xml and adds the DMX range to the channel's ranges.\n   * @param {XMLElement} xmlNode A <step> or <range> element.\n   * @param {number} channelIndex The index of the channel that contains this capability.\n   */\n  function addCapability(xmlNode, channelIndex) {\n    const mindmx = Number.parseInt(xmlNode.$.mindmx, 10);\n    const maxdmx = Number.parseInt(xmlNode.$.maxdmx, 10);\n    const range = new Range([Math.min(mindmx, maxdmx), Math.max(mindmx, maxdmx)]);\n\n    if (channelIndex === -1) {\n      errors.push(`Capability ${range} is not inside a channel function.`);\n    }\n    else if (range.start < 0 || range.end > 255) {\n      errors.push(`Capability ${range} in channel ${channelIndex + 1} is out of the allowed 0…255 range.`);\n    }\n    else {\n      const existingRanges = usedChannelRanges[channelIndex];\n\n      if (range.overlapsWithOneOf(existingRanges)) {\n        errors.push(`Capability ${range} in channel ${channelIndex + 1} overlaps with other capabilities.`);\n      }\n      else {\n        existingRanges.push(range);\n      }\n    }\n\n    if ('minval' in xmlNode.$) {\n      const minval = Number.parseInt(xmlNode.$.minval, 10);\n      const maxval = Number.parseInt(xmlNode.$.maxval, 10);\n\n      if (minval > maxval) {\n        errors.push(`Capability ${range} in channel ${channelIndex + 1} must not use a greater minval (${minval}) than maxval (${maxval}). Instead, swap mindmx and maxdmx.`);\n      }\n    }\n  }\n\n  /**\n   * Checks that:\n   * - All not NoFunction channels have been used.\n   * - No NoFunction channels have been used.\n   * - Each channel has either no capability at all or its ranges span the whole 0…255 range.\n   */\n  function checkUsedChannels() {\n    for (const [index, channel] of exportMode.channels.entries()) {\n      const isUsed = index in usedChannelRanges;\n      const isNoFunction = isNoFunctionChannel(channel);\n\n      if (isUsed) {\n        if (isNoFunction) {\n          errors.push(`Channel ${index + 1} \"${channel.name}\" of type NoFunction should be omitted.`);\n        }\n        else {\n          const mergedRanges = Range.getMergedRanges(usedChannelRanges[index]);\n\n          if (!areRangesComplete(mergedRanges)) {\n            const usedRanges = mergedRanges.join(', ');\n            errors.push(`Channel ${index + 1} \"${channel.name}\" is missing capabilities. Used ranges: ${usedRanges}`);\n          }\n        }\n      }\n      else if (!isNoFunction) {\n        errors.push(`Channel ${index + 1} \"${channel.name}\" is missing.`);\n      }\n    }\n\n    /**\n     * @param {AbstractChannel} channel The channel to check.\n     * @returns {boolean} Whether the given channel is of type NoFunction. If it is a switching channel, the default channel is checked.\n     */\n    function isNoFunctionChannel(channel) {\n      if (channel.type === 'NoFunction') {\n        return true;\n      }\n\n      if (channel instanceof SwitchingChannel) {\n        return isNoFunctionChannel(channel.defaultChannel);\n      }\n\n      return false;\n    }\n  }\n\n  /**\n   * @param {Range[]} ranges A channel's found ranges with adjacent ones already merged.\n   * @returns {boolean} True if there's only one 0…255 range or no range at all.\n   */\n  function areRangesComplete(ranges) {\n    if (ranges.length === 0) {\n      // no capabilities used\n      return true;\n    }\n\n    if (ranges.length > 1) {\n      // more than one range -> could not be merged to 0…255\n      return false;\n    }\n\n    const range = ranges[0];\n    return range.start === 0 && range.end === 255;\n  }\n}\n"
  },
  {
    "path": "plugins/dmxcontrol3/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"DMXControl 3 (DDF3)\",\n  \"description\": [\n    \"<p>Free lighting software, especially common in Germany, developed and\",\n    \"distributed by the non-profit association DMXControl Projects e.V.,\",\n    \"works only on Windows.</p>\",\n    \"\",\n    \"<p>This plugin handles <em>Device Definition Files</em> (<em>DDF</em>)\",\n    \"of version 3, used in DMXControl 3. They are saved as XML files\",\n    \"(one file per mode) and can be created with the DDFCreator program.</p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://www.dmxcontrol.de/\",\n    \"Tutorial on how to create a device definition (German)\": \"https://wiki-de.dmxcontrol-projects.org/index.php?title=Lektion_20_Tut3\",\n    \"Device definition specification (German)\": \"https://wiki-de.dmxcontrol-projects.org/index.php?title=DDF_DMXC3\"\n  },\n  \"fixtureUsage\": [\n    \"<p>Import fixture in Device Listing window (Devices &gt; Device Listing),\",\n    \"then patch it (Display &gt; Patch).</p>\"\n  ],\n  \"fileLocations\": {\n    \"subDirectoriesAllowed\": false,\n    \"Windows\": {\n      \"main\": \"C:\\\\Program Files\\\\DMXControl3\\\\Kernel\\\\Devices\\\\\"\n    }\n  },\n  \"additionalInfo\": [\n    \"<p>Definition files may be stored in subfolders, but the filenames still\",\n    \"need to be unique (<code>Devices\\\\manA\\\\fix123.xml</code> and\",\n    \"<code>Devices\\\\manB\\\\fix123.xml</code> doesn't work). Note that the\",\n    \"DDFCreator software doesn't recognize subfolders.</p>\"\n  ],\n  \"helpWanted\": \"Note that this plugin does not produce very reliable DDF3 fixture definitions yet, so please double-check the output and report any issues. Code contributions via pull requests are of course very welcome!\"\n}\n"
  },
  {
    "path": "plugins/dragonframe/export.js",
    "content": "import fixtureJsonStringify from '../../lib/fixture-json-stringify.js';\nimport importJson from '../../lib/import-json.js';\n/** @import Fixture from '../../lib/model/Fixture.js' */\n\n// needed for export test\nexport const supportedOflVersion = '12.2.1';\n\nexport const version = '1.0.0';\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const usedManufacturers = new Set();\n\n  // one JSON file for each fixture\n  const files = fixtures.map((fixture) => {\n    usedManufacturers.add(fixture.manufacturer.key);\n\n    try {\n      return getFixtureFile(fixture);\n    }\n    catch (error) {\n      throw new Error(`Exporting fixture ${fixture.manufacturer.key}/${fixture.key} failed: ${error}`, {\n        cause: error,\n      });\n    }\n  });\n\n  const manufacturers = await importJson('../../fixtures/manufacturers.json', import.meta.url);\n\n  // manufacturers.json file\n  const usedManufacturerData = {\n    $schema: `https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/schema-${supportedOflVersion}/schemas/manufacturers.json`,\n  };\n  for (const manufacturer of Object.keys(manufacturers).toSorted()) {\n    if (usedManufacturers.has(manufacturer)) {\n      usedManufacturerData[manufacturer] = manufacturers[manufacturer];\n    }\n  }\n  files.push({\n    name: 'manufacturers.json',\n    content: `${JSON.stringify(usedManufacturerData, null, 2)}\\n`,\n    mimetype: 'application/dragonframe-manufacturers',\n  });\n\n  return files;\n}\n\n/**\n * @param {Fixture} fixture The fixture to export.\n * @returns {object} The generated fixture JSON file.\n */\nfunction getFixtureFile(fixture) {\n  const jsonData = structuredClone(fixture.jsonObject);\n  jsonData.$schema = `https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/schema-${supportedOflVersion}/schemas/fixture.json`;\n\n  jsonData.fixtureKey = fixture.key;\n  jsonData.manufacturerKey = fixture.manufacturer.key;\n  jsonData.oflURL = fixture.url;\n\n  downgradePhysical(jsonData.physical);\n\n  for (const mode of jsonData.modes) {\n    downgradePhysical(mode.physical);\n  }\n\n  return {\n    name: `${fixture.manufacturer.key}/${fixture.key}.json`,\n    content: fixtureJsonStringify(jsonData),\n    mimetype: 'application/dragonframe-fixture',\n    fixtures: [fixture],\n  };\n}\n\n/**\n * Removes `powerConnectors` from physical.\n * @param {object|undefined} physicalJsonData The physical object to transform.\n */\nfunction downgradePhysical(physicalJsonData) {\n  if (physicalJsonData) {\n    delete physicalJsonData.powerConnectors;\n  }\n}\n"
  },
  {
    "path": "plugins/dragonframe/exportTests/json-schema-conformity.js",
    "content": "import https from 'https';\nimport Ajv from 'ajv';\nimport addFormats from 'ajv-formats';\nimport getAjvErrorMessages from '../../../lib/get-ajv-error-messages.js';\nimport { supportedOflVersion as SUPPORTED_OFL_VERSION } from '../export.js';\n\nconst REPO_BASE_URL = 'https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library';\nconst SCHEMA_BASE_URL = `${REPO_BASE_URL}/schema-${SUPPORTED_OFL_VERSION}/schemas/`;\nconst SCHEMA_FILES = [\n  'capability.json',\n  'channel.json',\n  'definitions.json',\n  'fixture.json',\n  'gobo.json',\n  'matrix.json',\n  'manufacturers.json',\n  'wheel-slot.json',\n];\n\nconst schemas = await getSchemas();\n\n/**\n * @typedef {object} ExportFile\n * @property {string} name File name,\n * may include slashes to provide a folder structure.\n * @property {string} content File content.\n * @property {string} mimetype File mime type.\n * @property {Fixture[] | null} fixtures Fixture objects that are described in given file; may be omitted if the file doesn't belong to any fixture (e.g. manufacturer information).\n * @property {string | null} mode Mode's shortName if given file only describes a single mode.\n */\n\n/**\n * @param {ExportFile} exportFile The file returned by the plugins' export module.\n * @param {ExportFile[]} allExportFiles An array of all export files.\n * @returns {Promise<void, string[] | string>} Resolve when the test passes or reject with an array of errors or one error if the test fails.\n */\nexport default async function testJsonSchemaConformity(exportFile, allExportFiles) {\n  const ajv = new Ajv({\n    schemas,\n    strict: false,\n    verbose: true,\n  });\n  addFormats(ajv);\n  ajv.addFormat('color-hex', true);\n\n  const schemaName = exportFile.name === 'manufacturers.json' ? 'manufacturers' : 'fixture';\n  const schemaValidate = ajv.getSchema(`${REPO_BASE_URL}/master/schemas/${schemaName}.json`);\n\n  const schemaValid = schemaValidate(JSON.parse(exportFile.content));\n  if (!schemaValid) {\n    throw getAjvErrorMessages(schemaValidate.errors, 'fixture');\n  }\n}\n\n/**\n * @returns {Promise<object[]>} Asynchronously downloaded and JSON parsed schemas.\n */\nasync function getSchemas() {\n  const schemasJson = await Promise.all(SCHEMA_FILES.map(\n    (filename) => downloadSchema(SCHEMA_BASE_URL + filename),\n  ));\n\n  const fixtureSchema = schemasJson[SCHEMA_FILES.indexOf('fixture.json')];\n  const definitionsSchema = schemasJson[SCHEMA_FILES.indexOf('definitions.json')];\n  const manufacturersSchema = schemasJson[SCHEMA_FILES.indexOf('manufacturers.json')];\n\n  // allow automatically added properties (but don't validate them)\n  fixtureSchema.properties.fixtureKey = true;\n  fixtureSchema.properties.manufacturerKey = true;\n  fixtureSchema.properties.oflURL = true;\n\n  // allow resolved gobo resources\n  definitionsSchema.goboResourceString = { type: 'object' };\n\n  // allow changed schema property\n  fixtureSchema.properties.$schema = { const: `${SCHEMA_BASE_URL}fixture.json` };\n  fixtureSchema.patternProperties = undefined;\n  manufacturersSchema.properties = { $schema: { const: `${SCHEMA_BASE_URL}manufacturers.json` } };\n  manufacturersSchema.patternProperties = undefined;\n\n  return schemasJson;\n}\n\n/**\n * @param {string} url The schema URL to fetch\n * @returns {Promise<object>} A promise resolving to the JSON Schema object.\n */\nfunction downloadSchema(url) {\n  return new Promise((resolve, reject) => {\n    const request = https.get(url, (response) => {\n      if (response.statusCode < 200 || response.statusCode > 299) {\n        reject(new Error(`Failed to load page, status code: ${response.statusCode}`));\n      }\n\n      let body = '';\n      response.on('data', (chunk) => {\n        body += chunk;\n      });\n      response.on('end', () => resolve(JSON.parse(body)));\n    });\n\n    request.on('error', (error) => reject(error));\n  });\n}\n"
  },
  {
    "path": "plugins/dragonframe/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"Dragonframe\",\n  \"description\": [\n    \"<p><em>Dragonframe</em> is software for stop motion filmmaking, with DMX programming capabilities.\",\n    \"Dragonframe 5 will support lighting fixtures.\",\n    \"The fixture format is essentially\",\n    \"<a href=\\\"https://github.com/OpenLightingProject/open-fixture-library/blob/schema-12.2.1/docs/fixture-format.md\\\">\",\n    \"the OFL format at schema version 12.2.1</a></p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://www.dragonframe.com/\"\n  },\n  \"fixtureUsage\": [\n    \"<p>Dragonframe will include light fixture definitions.</p>\",\n    \"<p>If you need to add new ones, you can create them manually or via the OFL website\",\n    \"and place the JSON files in the user directory specified below.</p>\"\n  ],\n  \"fileLocations\": {\n    \"subDirectoriesAllowed\": true,\n    \"Windows\": {\n      \"user\": \"C:\\\\Users\\\\yourUsername\\\\Dragonframe\\\\LightFixtures\"\n    },\n    \"Mac OS\": {\n      \"user\": \"~/Dragonframe/LightFixtures\"\n    },\n    \"Linux\": {\n      \"user\": \"~/Dragonframe/LightFixtures\"\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/ecue/export.js",
    "content": "import xmlbuilder from 'xmlbuilder';\nimport CoarseChannel from '../../lib/model/CoarseChannel.js';\nimport FineChannel from '../../lib/model/FineChannel.js';\nimport NullChannel from '../../lib/model/NullChannel.js';\nimport Physical from '../../lib/model/Physical.js';\nimport SwitchingChannel from '../../lib/model/SwitchingChannel.js';\n/** @import Fixture from '../../lib/model/Fixture.js' */\n/** @import Mode from '../../lib/model/Mode.js' */\n\nexport const version = '0.3.0';\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const timestamp = dateToString(options.date);\n\n  const manufacturers = {};\n  for (const fixture of fixtures) {\n    const manufacturer = fixture.manufacturer.key;\n    if (!(manufacturer in manufacturers)) {\n      manufacturers[manufacturer] = {\n        data: fixture.manufacturer,\n        fixtures: [],\n      };\n    }\n    manufacturers[manufacturer].fixtures.push(fixture);\n  }\n\n  const xml = xmlbuilder.create(\n    {\n      Document: {\n        '@Owner': 'user',\n        '@TypeVersion': 2,\n        '@SaveTimeStamp': timestamp,\n      },\n    },\n    {\n      version: '1.0',\n      encoding: 'utf-8',\n      standalone: true,\n    },\n  );\n\n  const xmlLibrary = xml.element({\n    Library: {},\n  });\n  const xmlFixtures = xmlLibrary.element({\n    Fixtures: {},\n  });\n  const xmlTiles = xmlLibrary.element({\n    Tiles: {},\n  });\n\n  for (const manufacturer of Object.keys(manufacturers)) {\n    const manufacturerAttributes = {\n      _CreationDate: timestamp,\n      _ModifiedDate: timestamp,\n      Name: manufacturers[manufacturer].data.name,\n      Comment: manufacturers[manufacturer].data.comment,\n      Web: manufacturers[manufacturer].data.website || '',\n    };\n    xmlTiles.element('Manufacturer', manufacturerAttributes);\n\n    const xmlManufacturerFixtures = xmlFixtures.element('Manufacturer', manufacturerAttributes);\n    for (const fixture of manufacturers[manufacturer].fixtures) {\n      addFixture(xmlManufacturerFixtures, fixture);\n    }\n  }\n\n  return [{\n    name: 'UserLibrary.xml',\n    content: xml.end({\n      pretty: true,\n      indent: '    ',\n    }),\n    mimetype: 'application/xml',\n    fixtures,\n  }];\n}\n\n/**\n * @param {object} xmlManufacturer The xmlbuilder <Manufacturer> object.\n * @param {Fixture} fixture The OFL fixture object.\n */\nfunction addFixture(xmlManufacturer, fixture) {\n  try {\n    const fixtureCreationDate = dateToString(fixture.meta.createDate);\n    const fixtureModifiedDate = dateToString(fixture.meta.lastModifyDate);\n\n    for (const mode of fixture.modes) {\n      const physical = mode.physical || new Physical({});\n\n      const xmlFixture = xmlManufacturer.element('Fixture', {\n        _CreationDate: fixtureCreationDate,\n        _ModifiedDate: fixtureModifiedDate,\n        Name: fixture.name + (fixture.modes.length > 1 ? ` (${mode.shortName} mode)` : ''),\n        NameShort: fixture.shortName + (fixture.modes.length > 1 ? `-${mode.shortName}` : ''),\n        Comment: getFixtureComment(fixture),\n        AllocateDmxChannels: mode.channels.length,\n        Weight: physical.weight || 0,\n        Power: physical.power || 0,\n        DimWidth: physical.width || 10,\n        DimHeight: physical.height || 10,\n        DimDepth: physical.depth || 10,\n      });\n\n      handleMode(xmlFixture, mode);\n    }\n  }\n  catch (error) {\n    throw new Error(`Exporting fixture ${fixture.manufacturer.key}/${fixture.key} failed: ${error}`, {\n      cause: error,\n    });\n  }\n}\n\n/**\n * @param {object} xmlFixture The xmlbuilder <Fixture> object.\n * @param {Mode} mode The OFL mode object.\n */\nfunction handleMode(xmlFixture, mode) {\n  let viewPosCount = 1;\n  for (let dmxCount = 0; dmxCount < mode.channels.length; dmxCount++) {\n    let channel = mode.channels[dmxCount];\n\n    // skip unused channels\n    if (channel instanceof NullChannel) {\n      continue;\n    }\n\n    const channelName = channel.name;\n\n    // ecue doesn't support switching channels, so we just use the default channel's data\n    if (channel instanceof SwitchingChannel) {\n      channel = channel.defaultChannel;\n    }\n\n    let fineChannelKey = null;\n    if (channel instanceof FineChannel) {\n      if (channel.resolution === CoarseChannel.RESOLUTION_16BIT) {\n        // ignore this channel, we handle it together with its coarse channel\n        continue;\n      }\n\n      // just pretend its a single channel and use coarse channel's data\n      fineChannelKey = channel.key;\n      channel = channel.coarseChannel;\n    }\n\n    const dmxByte0 = dmxCount + 1;\n    let dmxByte1 = 0;\n    let resolution = CoarseChannel.RESOLUTION_8BIT;\n\n    if (fineChannelKey === null && channel.fineChannelAliases.length > 0) {\n      dmxByte1 = mode.getChannelIndex(channel.fineChannelAliases[0], 'defaultOnly') + 1;\n      resolution = Math.min(CoarseChannel.RESOLUTION_16BIT, channel.getResolutionInMode(mode, 'defaultOnly'));\n    }\n\n    const defaultValue = channel.getDefaultValueWithResolution(resolution);\n    const highlightValue = channel.getHighlightValueWithResolution(resolution);\n\n    const xmlChannel = xmlFixture.element(getChannelType(channel), {\n      Name: channelName,\n      DefaultValue: defaultValue,\n      Highlight: highlightValue,\n      Deflection: 0,\n      DmxByte0: dmxByte0,\n      DmxByte1: dmxByte1,\n      Constant: channel.isConstant ? 1 : 0,\n      Crossfade: channel.canCrossfade ? 1 : 0,\n      Invert: channel.isInverted ? 1 : 0,\n      Precedence: channel.precedence,\n      ClassicPos: viewPosCount,\n    });\n\n    if (fineChannelKey === null) {\n      addCapabilities(xmlChannel, channel, resolution);\n    }\n\n    viewPosCount++;\n  }\n}\n\n/**\n * @param {Fixture} fixture The OFL fixture object.\n * @returns {string} The comment to use in the exported fixture.\n */\nfunction getFixtureComment(fixture) {\n  const generatedString = `generated by the Open Fixture Library – ${fixture.url}`;\n  if (fixture.hasComment) {\n    return `${fixture.comment} (${generatedString})`;\n  }\n  return generatedString;\n}\n\n/**\n * @param {CoarseChannel} channel The OFL channel object.\n * @returns {string} The e:cue channel type for the channel.\n */\nfunction getChannelType(channel) {\n  switch (channel.type) {\n    case 'Multi-Color':\n    case 'Single Color':\n    case 'Color Temperature': {\n      return 'ChannelColor';\n    }\n    case 'Iris':\n    case 'Zoom':\n    case 'Shutter':\n    case 'Strobe':\n    case 'Gobo':\n    case 'Prism':\n    case 'Effect':\n    case 'Speed':\n    case 'Maintenance':\n    case 'NoFunction': {\n      return 'ChannelBeam';\n    }\n    case 'Pan':\n    case 'Tilt':\n    case 'Focus': {\n      return 'ChannelFocus';\n    }\n    case 'Intensity':\n    case 'Fog':\n    default: {\n      return 'ChannelIntensity';\n    }\n  }\n}\n\n/**\n * @param {object} xmlChannel The xmlbuilder <Channel*> object.\n * @param {CoarseChannel} channel The OFL channel object.\n * @param {number} resolution The resolution of the channel in the current mode.\n */\nfunction addCapabilities(xmlChannel, channel, resolution) {\n  for (const capability of channel.capabilities) {\n    const dmxRange = capability.getDmxRangeWithResolution(resolution);\n    xmlChannel.element('Range', {\n      Name: capability.name,\n      Start: dmxRange.start,\n      End: dmxRange.end,\n      AutoMenu: capability.menuClick === 'hidden' ? 0 : 1,\n      Centre: capability.menuClick === 'center' ? 1 : 0,\n    });\n  }\n}\n\n/**\n * @param {Date} date The date to format.\n * @returns {string} The date in YYYY-MM-DD#HH:mm:ss format.\n */\nfunction dateToString(date) {\n  return date.toISOString().replace(/T/, '#').replace(/\\..+/, '');\n}\n"
  },
  {
    "path": "plugins/ecue/import.js",
    "content": "import xml2js from 'xml2js';\nimport importJson from '../../lib/import-json.js';\n\n// see https://github.com/OpenLightingProject/open-fixture-library/issues/4415\nconst colorNameListPromise = importJson('../../node_modules/color-name-list/dist/colornames.json', import.meta.url);\n\nexport const version = '0.3.1';\n\n/**\n * @param {Buffer} buffer The imported file.\n * @param {string} filename The imported file's name.\n * @param {string} authorName The importer's name.\n * @returns {Promise<object, Error>} A Promise resolving to an out object\n */\nexport async function importFixtures(buffer, filename, authorName) {\n  const colorNameList = await colorNameListPromise;\n  const colors = {};\n  for (const color of colorNameList) {\n    colors[color.name.toLowerCase().replaceAll(/\\s/g, '')] = color.hex;\n  }\n  const timestamp = new Date().toISOString().replace(/T.*/, '');\n\n  const out = {\n    manufacturers: {},\n    fixtures: {},\n    warnings: {},\n  };\n\n  const xml = await xml2js.parseStringPromise(buffer.toString());\n\n  if (!('Library' in xml.Document) || !('Fixtures' in xml.Document.Library[0]) || !('Manufacturer' in xml.Document.Library[0].Fixtures[0])) {\n    throw new Error('Nothing to import.');\n  }\n\n  const ecueManufacturers = xml.Document.Library[0].Fixtures[0].Manufacturer || [];\n  for (const manufacturer of ecueManufacturers) {\n    addManufacturer(manufacturer);\n  }\n\n  return out;\n\n  /**\n   * Parses the e:cue manufacturer and adds it to `out.manufacturers`.\n   * Calls {@link addFixture} for all contained fixtures.\n   * @param {object} ecueManufacturer The e:cue manufacturer object.\n   */\n  function addManufacturer(ecueManufacturer) {\n    const manufacturerName = ecueManufacturer.$.Name;\n    const manufacturerKey = slugify(manufacturerName);\n\n    out.manufacturers[manufacturerKey] = {\n      name: manufacturerName,\n    };\n\n    if (ecueManufacturer.$.Comment !== '') {\n      out.manufacturers[manufacturerKey].comment = ecueManufacturer.$.Comment;\n    }\n    if (ecueManufacturer.$.Web !== '') {\n      out.manufacturers[manufacturerKey].website = ecueManufacturer.$.Web;\n    }\n\n    for (const fixture of (ecueManufacturer.Fixture || [])) {\n      addFixture(fixture, manufacturerKey);\n    }\n  }\n\n  /**\n   * Parses the e:cue fixture and add it to out.fixtures.\n   * @param {object} ecueFixture The e:cue fixture object.\n   * @param {string} manufacturerKey The manufacturer key of the fixture.\n   */\n  function addFixture(ecueFixture, manufacturerKey) {\n    const fixture = {\n      $schema: 'https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json',\n      name: ecueFixture.$.Name,\n    };\n\n    let fixtureKey = `${manufacturerKey}/${slugify(fixture.name)}`;\n    if (fixtureKey in out.fixtures) {\n      fixtureKey += `-${Math.random().toString(36).slice(2, 7)}`;\n      out.warnings[fixtureKey] = [`Fixture key '${fixtureKey}' is not unique, appended random characters.`];\n    }\n    else {\n      out.warnings[fixtureKey] = [];\n    }\n\n    if (ecueFixture.$.NameShort !== '') {\n      fixture.shortName = ecueFixture.$.NameShort;\n    }\n\n    fixture.categories = ['Other'];\n    out.warnings[fixtureKey].push('Please specify categories.');\n\n    fixture.meta = {\n      authors: [authorName],\n      createDate: ecueFixture.$._CreationDate.replace(/#.*/, ''),\n      lastModifyDate: ecueFixture.$._ModifiedDate.replace(/#.*/, ''),\n      importPlugin: {\n        plugin: 'ecue',\n        date: timestamp,\n      },\n    };\n\n    if (ecueFixture.$.Comment !== '') {\n      fixture.comment = ecueFixture.$.Comment;\n    }\n\n    const physical = getPhysical(ecueFixture);\n    if (JSON.stringify(physical) !== '{}') {\n      fixture.physical = physical;\n    }\n\n    fixture.availableChannels = {};\n\n    // ecue does not support modes, so we generate only one\n    fixture.modes = [{\n      name: `${ecueFixture.$.AllocateDmxChannels}-channel`,\n      shortName: `${ecueFixture.$.AllocateDmxChannels}ch`,\n      channels: [],\n    }];\n\n    for (const ecueChannel of getCombinedEcueChannels(ecueFixture)) {\n      addChannelToFixture(ecueChannel, fixture, out.warnings[fixtureKey], colors);\n    }\n\n    out.fixtures[fixtureKey] = fixture;\n  }\n}\n\n/**\n * @param {object} ecueFixture The e:cue fixture object.\n * @returns {object} The OFL fixture's physical object.\n */\nfunction getPhysical(ecueFixture) {\n  const physical = {};\n\n  if (ecueFixture.$.DimWidth !== '10' && ecueFixture.$.DimHeight !== '10' && ecueFixture.$.DimDepth !== '10') {\n    physical.dimensions = [\n      Number.parseFloat(ecueFixture.$.DimWidth),\n      Number.parseFloat(ecueFixture.$.DimHeight),\n      Number.parseFloat(ecueFixture.$.DimDepth),\n    ];\n  }\n\n  if (ecueFixture.$.Weight !== '0') {\n    physical.weight = Number.parseFloat(ecueFixture.$.Weight);\n  }\n\n  if (ecueFixture.$.Power !== '0') {\n    physical.power = Number.parseFloat(ecueFixture.$.Power);\n  }\n\n  return physical;\n}\n\n/**\n * @param {object} ecueFixture The e:cue fixture object.\n * @returns {object[]} An array of all ecue channel objects.\n */\nfunction getCombinedEcueChannels(ecueFixture) {\n  const channels = [];\n\n  const channelTypes = ['ChannelIntensity', 'ChannelColor', 'ChannelBeam', 'ChannelFocus'];\n  for (const channelType of channelTypes) {\n    if (ecueFixture[channelType]) {\n      channels.push(...ecueFixture[channelType].map((channel) => {\n        // save the channel type in the channel object\n        channel._ecueChannelType = channelType;\n        return channel;\n      }));\n    }\n  }\n\n  // sort channels by (coarse) DMX channel\n  channels.sort((a, b) => Number.parseInt(a.$.DmxByte0, 10) - Number.parseInt(b.$.DmxByte0, 10));\n\n  return channels;\n}\n\n/**\n * @param {string | undefined} direction A string containing something like \"CW\", \"CCW\", \"clockwise\", \"counter-clockwise\".\n * @returns {string} The normalized direction suffix.\n */\nfunction getDirectionSuffix(direction) {\n  if (!direction) {\n    return '';\n  }\n\n  return /^(?:clockwise|cw),?\\s+$/i.test(direction) ? ' CW' : ' CCW';\n}\n\n/**\n * Parses the e:cue channel and adds it to OFL fixture's availableChannels and the first mode.\n * @param {object} ecueChannel The e:cue channel object.\n * @param {object} fixture The OFL fixture object.\n * @param {string[]} warningsArray This fixture's warnings array in the `out` object.\n * @param {object} colors A map from lowercase spaceless color name to hex value.\n */\nfunction addChannelToFixture(ecueChannel, fixture, warningsArray, colors) {\n  const channel = {};\n\n  const channelName = ecueChannel.$.Name.trim();\n\n  let channelKey = channelName;\n  if (channelKey in fixture.availableChannels) {\n    warningsArray.push(`Channel key '${channelKey}' is not unique, appended random characters.`);\n    channelKey += `-${Math.random().toString(36).slice(2, 7)}`;\n    channel.name = channelName;\n  }\n\n  let maxDmxValue = 255;\n  if (ecueChannel.$.DmxByte1 !== '0') {\n    const shortNameFine = `${channelKey} fine`;\n    channel.fineChannelAliases = [shortNameFine];\n    maxDmxValue = (256 * 256) - 1;\n    fixture.modes[0].channels[Number.parseInt(ecueChannel.$.DmxByte1, 10) - 1] = shortNameFine;\n  }\n\n  addDmxValues();\n\n  if (!('Range' in ecueChannel)) {\n    ecueChannel.Range = [{\n      $: {\n        Start: 0,\n        End: maxDmxValue,\n        Name: '0-100%',\n        AutoMenu: '1',\n        Centre: '0',\n      },\n    }];\n  }\n\n  channel.capabilities = ecueChannel.Range.map(\n    (ecueRange, index) => getCapability(ecueRange, index),\n  );\n\n  if (channel.capabilities.length === 1) {\n    channel.capability = channel.capabilities[0];\n    delete channel.capabilities;\n    delete channel.capability.dmxRange;\n  }\n\n  fixture.availableChannels[channelKey] = channel;\n  fixture.modes[0].channels[Number.parseInt(ecueChannel.$.DmxByte0, 10) - 1] = channelKey;\n\n  /**\n   * Adds DMX value related properties to channel.\n   */\n  function addDmxValues() {\n    if (ecueChannel.$.DefaultValue !== '0') {\n      channel.defaultValue = Number.parseInt(ecueChannel.$.DefaultValue, 10);\n    }\n\n    if (ecueChannel.$.Highlight !== '0') {\n      channel.highlightValue = Number.parseInt(ecueChannel.$.Highlight, 10);\n    }\n\n    if (ecueChannel.$.Constant === '1') {\n      channel.constant = true;\n    }\n\n    if (ecueChannel.$.Precedence === 'HTP') {\n      channel.precedence = 'HTP';\n    }\n  }\n\n  /**\n   *\n   * @param {object} ecueRange The e:cue range object.\n   * @param {number} index The index of the capability / range.\n   * @returns {object} The OFL capability object.\n   */\n  function getCapability(ecueRange, index) {\n    const capability = {\n      dmxRange: getDmxRange(),\n    };\n\n    const capabilityName = ecueRange.$.Name.trim();\n\n    capability.type = getCapabilityType();\n\n    const setPanTiltAngles = () => {\n      capability.angleStart = '0%';\n      capability.angleEnd = '100%';\n      capability.comment = capabilityName;\n    };\n\n    // capability parsers can rely on the channel type as a first distinctive feature\n    const capabilityTypeParsers = {\n      ColorIntensity() {\n        capability.color = ['Red', 'Green', 'Blue', 'Cyan', 'Magenta', 'Yellow', 'Amber', 'Warm White', 'Cold White', 'White', 'UV', 'Lime'].find(\n          (color) => channelName.toLowerCase().includes(color.toLowerCase()),\n        );\n\n        capability.comment = capabilityName;\n      },\n      WheelSlot() {\n        if (ecueChannel._ecueChannelType === 'ChannelColor') {\n          const color = capabilityName.toLowerCase().replace(/\\bgray\\b/, 'grey').replaceAll(/\\s/g, '');\n          if (color in colors) {\n            capability.colors = [colors[color]];\n          }\n        }\n\n        capability.comment = getSpeedGuessedComment();\n\n        if ('speedStart' in capability) {\n          capability.type = ecueChannel._ecueChannelType === 'ChannelColor' ? 'WheelRotation' : 'WheelSlotRotation';\n        }\n      },\n      ColorPreset() {\n        const color = capabilityName.toLowerCase().replace(/\\bgray\\b/, 'grey').replaceAll(/\\s/g, '');\n        if (color in colors) {\n          capability.color = colors[color];\n        }\n\n        capability.comment = capabilityName;\n      },\n      ShutterStrobe() {\n        if (/^(?:blackout|(?:shutter )?closed?)$/i.test(capabilityName)) {\n          capability.shutterEffect = 'Closed';\n          return;\n        }\n\n        if (/^(?:(?:shutter )?open|full?)$/i.test(capabilityName)) {\n          capability.shutterEffect = 'Open';\n          return;\n        }\n\n        if (/puls/i.test(capabilityName)) {\n          capability.shutterEffect = 'Pulse';\n        }\n        else if (/ramp\\s*up/i.test(capabilityName)) {\n          capability.shutterEffect = 'RampUp';\n        }\n        else if (/ramp\\s*down/i.test(capabilityName)) {\n          capability.shutterEffect = 'RampDown';\n        }\n        else {\n          capability.shutterEffect = 'Strobe';\n        }\n\n        if (/random/i.test(capabilityName)) {\n          capability.shutterEffect += 'Random';\n        }\n\n        capability.comment = getSpeedGuessedComment();\n      },\n      Pan: setPanTiltAngles,\n      Tilt: setPanTiltAngles,\n      Effect() {\n        capability.effectName = ''; // set it first here so effectName is before speedStart/speedEnd\n        capability.effectName = getSpeedGuessedComment();\n      },\n      NoFunction() {\n        // don't even add a comment\n      },\n    };\n\n    if (capability.type in capabilityTypeParsers) {\n      capabilityTypeParsers[capability.type]();\n    }\n    else {\n      capability.comment = getSpeedGuessedComment();\n    }\n\n    // delete unnecessary comments\n    if ('comment' in capability && (capability.comment === channelName || /^$|^0%?\\s*(?:-|to|–|…|\\.{2,}|->|<->|→)\\s*100%$/.test(capability.comment))) {\n      delete capability.comment;\n    }\n\n    if (ecueRange.$.AutoMenu !== '1') {\n      capability.menuClick = 'hidden';\n    }\n    else if (ecueRange.$.Centre !== '0') {\n      capability.menuClick = 'center';\n    }\n\n    return capability;\n\n    /**\n     * @returns {number[]} The DMX range of this capability.\n     */\n    function getDmxRange() {\n      const dmxRangeStart = Number.parseInt(ecueRange.$.Start, 10);\n      let dmxRangeEnd = Number.parseInt(ecueRange.$.End, 10);\n\n      if (dmxRangeEnd === -1) {\n        dmxRangeEnd = (index + 1 < ecueChannel.Range.length) ? Number.parseInt(ecueChannel.Range[index + 1].$.Start, 10) - 1 : maxDmxValue;\n      }\n\n      return [dmxRangeStart, dmxRangeEnd];\n    }\n\n    /**\n     * @returns {string} The parsed capability type.\n     */\n    function getCapabilityType() {\n      // capability parsers can rely on the channel type as a first distinctive feature\n      const capabilityTypePerChannelType = {\n        ChannelColor() {\n          if (/\\bcto\\b|\\bctb\\b|temperature\\b/i.test(channelName)) {\n            return 'ColorTemperature';\n          }\n\n          if (ecueChannel.Range.length === 1 && !/macro|wheel\\b/i.test(channelName)) {\n            return 'ColorIntensity';\n          }\n\n          if (/wheel\\b/i.test(channelName)) {\n            return 'WheelSlot';\n          }\n\n          return 'ColorPreset';\n        },\n        ChannelIntensity() {\n          // fall back to default\n          return capabilityTypePerChannelType.ChannelBeam();\n        },\n        ChannelFocus() {\n          if (/speed/i.test(channelName)) {\n            return 'PanTiltSpeed';\n          }\n\n          const isPan = channelName.match(/pan/i);\n          const isTilt = channelName.match(/tilt/i);\n\n          if ((!isPan && !isTilt) || (isPan && isTilt)) {\n            // fall back to default\n            return capabilityTypePerChannelType.ChannelBeam();\n          }\n\n          const panOrTilt = isPan ? 'Pan' : 'Tilt';\n\n          if (/continuous/i.test(channelName)) {\n            return `${panOrTilt}Continuous`;\n          }\n\n          return panOrTilt;\n        },\n        ChannelBeam() {\n          const capabilityTypeRegexps = {\n            NoFunction: /^(?:nothing|no func(?:tion)?|unused|not used|empty|no strobe|no prism|no frost)$/,\n            StrobeSpeed: /\\bstrobe speed\\b/,\n            StrobeDuration: /\\bstrobe duration\\b/,\n            ShutterStrobe: /\\b(?:shutter|strobe|strb|strob|strobing)\\b/,\n            Intensity: /\\b(?:intensity|dimmer)\\b/,\n            PanTiltSpeed: /\\b(?:pan[ /-]?tilt speed|p[ /-]?t speed)\\b/,\n            PanContinuous: /\\bpan continuous\\b/,\n            TiltContinuous: /\\btilt continuous\\b/,\n            EffectParameter: /\\beffect param(?:eter)?\\b/,\n            EffectSpeed: /\\beffect speed\\b/,\n            EffectDuration: /\\beffect duration\\b/,\n            Effect: /\\beffect\\b/,\n            SoundSensitivity: /\\b(?:sound|mic|microphone) sensitivity\\b/,\n            WheelShake: /\\bgobo shake\\b/,\n            WheelSlotRotation: /\\bgobo rot(?:ation)?\\b/,\n            WheelRotation: /wheel rot(?:ation)?\\b/,\n            WheelSlot: /\\bgobo\\b/,\n            BeamAngle: /\\bbeam angle\\b/,\n            BeamPosition: /\\b(beam|horizontal|vertical) position\\b/,\n            Focus: /\\bfocus\\b/,\n            Zoom: /\\bzoom\\b/,\n            IrisEffect: /\\biris effect\\b/,\n            Iris: /\\biris\\b/,\n            FrostEffect: /\\bfrost effect\\b/,\n            Frost: /\\bfrost\\b/,\n            PrismRotation: /\\bprisma? rot(?:ation)?\\b/,\n            Prism: /\\bprisma?\\b/,\n            BladeInsertion: /\\bblade insertion\\b/,\n            BladeRotation: /\\bblade rot(?:ation)?\\b/,\n            BladeSystemRotation: /\\bblade system rot(?:ation)?\\b/,\n            FogOutput: /\\bfog output\\b/,\n            FogType: /\\bfog type\\b/,\n            Fog: /\\bfog\\b/,\n            Rotation: /\\brotation\\b/,\n            Speed: /\\bspeed\\b/,\n            Time: /\\btime\\b/,\n            Maintenance: /\\b(?:reset|maintenance)\\b/,\n          };\n\n          return Object.keys(capabilityTypeRegexps).find(\n            (channelType) =>\n              capabilityName.toLowerCase().match(capabilityTypeRegexps[channelType])\n              || channelName.toLowerCase().match(capabilityTypeRegexps[channelType]),\n          ) || 'Generic';\n        },\n      };\n\n      return capabilityTypePerChannelType[ecueChannel._ecueChannelType]();\n    }\n\n    /**\n     * Try to guess speedStart / speedEnd from the capabilityName. May set cap.type to Rotation.\n     * @returns {string} The rest of the capabilityName.\n     */\n    function getSpeedGuessedComment() {\n      return capabilityName.replace(/(?:^|,\\s*|\\s+)\\(?((?:(?:counter-?)?clockwise|c?cw)(?:,\\s*|\\s+))?\\(?(slow|fast|\\d+|\\d+\\s*hz)\\s*(?:-|to|–|…|\\.{2,}|->|<->|→)\\s*(fast|slow|\\d+\\s*hz)\\)?$/i, (match, direction, start, end) => {\n        const directionSuffix = getDirectionSuffix(direction);\n        if (directionSuffix !== '') {\n          capability.type = 'Rotation';\n        }\n\n        start = start.toLowerCase();\n        end = end.toLowerCase();\n\n        const startNumber = Number.parseFloat(start);\n        const endNumber = Number.parseFloat(end);\n        if (!Number.isNaN(startNumber) && !Number.isNaN(endNumber)) {\n          start = `${startNumber}Hz`;\n          end = `${endNumber}Hz`;\n        }\n\n        capability.speedStart = start + directionSuffix;\n        capability.speedEnd = end + directionSuffix;\n\n        // delete the parsed part\n        return '';\n      });\n    }\n  }\n}\n\n/**\n * @param {string} string The string to slugify.\n * @returns {string} A slugified version of the string, i.e. only containing lowercase letters, numbers and dashes.\n */\nfunction slugify(string) {\n  return string.toLowerCase().replaceAll(/[^\\da-z-]+/g, ' ').trim().replaceAll(/\\s+/g, '-');\n}\n"
  },
  {
    "path": "plugins/ecue/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"e:cue\",\n  \"description\": [\n    \"<p><em>e:cue Lighting Application Suite</em>'s Programmer outputs DMX via\",\n    \"<em>e*net</em>, a proprietary network protocol that is only understood by\",\n    \"e:cue <em>Butler</em> dongles.</p>\",\n    \"\",\n    \"<p>A large (but a bit outdated) library is included. Some fixtures are\",\n    \"available from their support forum. New fixtures can be created and\",\n    \"imported in the <em>Library Editor</em> application.</p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://www.osram.com/ecue/\",\n    \"Support Forum\": \"https://www.osram.com/ecue/contact/ecue-forum/index.jsp\"\n  },\n  \"fixtureUsage\": [\n    \"<p>Open the <em>Library Editor</em> application. Then either right-click\",\n    \"<em>User Library</em> in the left panel and select <em>Merge Import…</em>,\",\n    \"or select <em>Library &gt; Extern &gt; Load/Convert…</em> in the menu and\",\n    \"select the downloaded file.</p>\"\n  ],\n  \"fileLocations\": {\n    \"subDirectoriesAllowed\": false,\n    \"Windows\": {\n      \"main\": \"C:\\\\ProgramData\\\\ecue\\\\Library V7.0\\\\MainLibrary.xml\",\n      \"user\": \"C:\\\\Documents and Settings\\\\[user name]\\\\AppData\\\\Local\\\\ecue\\\\Library V7.0\\\\UserLibrary.xml\"\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/gdtf/deprecated-gdtf-attributes.js",
    "content": "import { normalizeAngularSpeedDirection } from './gdtf-helpers.js';\n\nconst deprecatedGdtfAttributes = {\n  'ActiveZone': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'AnimationIndexRotate': {\n    // Controls the animation disk's index or its rotation speed.\n    // Replaced by AnimationWheel(n)Pos in GDTF v1.0\n    inheritFrom: 'AnimationWheel(n)Pos',\n  },\n  'AnimationIndexRotateMode': {\n    // Changes control between selecting, indexing, and rotating the animation wheel.\n    // Replaced by AnimationWheel(n)Mode in GDTF v1.0\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'AnimationOffset': {\n    // Controls the animation disk's shaking.\n    // Replaced by AnimationWheel(n)PosShake in GDTF v1.0\n    inheritFrom: 'AnimationWheel(n)PosShake',\n  },\n  'AnimationWheel': {\n    // Inserts a gobo disk into the beam. The disk has the ability to continuously index and rotate.\n    // Replaced by AnimationWheel(n) in GDTF v1.0\n    inheritFrom: 'AnimationWheel(n)',\n  },\n  'AnimationWheelMacro': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as AnimationWheel(n)Macro since GDTF v1.0\n    inheritFrom: 'AnimationWheel(n)Macro',\n  },\n  'AnimationWheelPos': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as AnimationWheel(n)Pos since GDTF v1.0\n    inheritFrom: 'AnimationWheel(n)Pos',\n  },\n  'AnimationWheelPosSpin': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as AnimationWheel(n)PosRotate since GDTF v1.0\n    inheritFrom: 'AnimationWheel(n)PosRotate',\n  },\n  'BeamMode': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'Blower': {\n    // Renamed to Blower(n) in GDTF v1.0\n    inheritFrom: 'Blower(n)',\n  },\n  'Color(n)Audio': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Color(n)WheelAudio since GDTF v0.88\n    inheritFrom: 'Color(n)WheelAudio',\n  },\n  'Color(n)Index': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Color(n)WheelIndex since GDTF v0.88\n    inheritFrom: 'Color(n)WheelIndex',\n  },\n  'Color(n)Random': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Color(n)WheelRandom since GDTF v0.88\n    inheritFrom: 'Color(n)WheelRandom',\n  },\n  'Color(n)Select': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Color(n)',\n  },\n  'Color(n)Spin': {\n    // Renamed to Color(n)WheelSpin in GDTF v0.88\n    inheritFrom: 'Color(n)WheelSpin',\n  },\n  'ColorMacroMSpeed': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'ColorRGB(n)': {\n    // Controls the intensity of the fixture's color emitters.\n    // Replaced by ColorRGB_* in GDTF v0.88\n    oflType: 'ColorIntensity',\n    oflProperty: 'brightness',\n    defaultPhysicalEntity: 'ColorComponent',\n    beforePhysicalPropertyHook(capability, gdtfCapability, attributeName) {\n      const rgbNumber = Number.parseInt(attributeName.slice(8), 10);\n\n      switch (rgbNumber) {\n        case 1: {\n          capability.color = guessColorComponentName(gdtfCapability, 'Red', 'Cyan');\n          break;\n        }\n        case 2: {\n          capability.color = guessColorComponentName(gdtfCapability, 'Green', 'Magenta');\n          break;\n        }\n        case 3: {\n          capability.color = guessColorComponentName(gdtfCapability, 'Blue', 'Yellow');\n          break;\n        }\n        case 4: {\n          capability.color = 'Amber';\n          break;\n        }\n        case 5: {\n          capability.color = 'White';\n          break;\n        }\n        default: {\n        // This is most likely wrong but enables the user to make an informed choice.\n          capability.color = gdtfCapability._channelFunction._attribute.$.Pretty || 'Unknown';\n        }\n      }\n    },\n  },\n  'ColorRGB_B': {\n    // Renamed to ColorAdd_B in GDTF v1.0\n    inheritFrom: 'ColorAdd_B',\n  },\n  'ColorRGB_BC': {\n    // Renamed to ColorAdd_BC in GDTF v1.0\n    inheritFrom: 'ColorAdd_BC',\n  },\n  'ColorRGB_BM': {\n    // Renamed to ColorAdd_BM in GDTF v1.0\n    inheritFrom: 'ColorAdd_BM',\n  },\n  'ColorRGB_C': {\n    // Renamed to ColorAdd_C in GDTF v1.0\n    inheritFrom: 'ColorAdd_C',\n  },\n  'ColorRGB_CW': {\n    // Renamed to ColorAdd_CW in GDTF v1.0\n    inheritFrom: 'ColorAdd_CW',\n  },\n  'ColorRGB_G': {\n    // Renamed to ColorAdd_G in GDTF v1.0\n    inheritFrom: 'ColorAdd_G',\n  },\n  'ColorRGB_GC': {\n    // Renamed to ColorAdd_GC in GDTF v1.0\n    inheritFrom: 'ColorAdd_GC',\n  },\n  'ColorRGB_GY': {\n    // Renamed to ColorAdd_GY in GDTF v1.0\n    inheritFrom: 'ColorAdd_GY',\n  },\n  'ColorRGB_M': {\n    // Renamed to ColorAdd_M in GDTF v1.0\n    inheritFrom: 'ColorAdd_M',\n  },\n  'ColorRGB_R': {\n    // Renamed to ColorAdd_R in GDTF v1.0\n    inheritFrom: 'ColorAdd_R',\n  },\n  'ColorRGB_RM': {\n    // Renamed to ColorAdd_RM in GDTF v1.0\n    inheritFrom: 'ColorAdd_RM',\n  },\n  'ColorRGB_RY': {\n    // Renamed to ColorAdd_RY in GDTF v1.0\n    inheritFrom: 'ColorAdd_RY',\n  },\n  'ColorRGB_UV': {\n    // Renamed to ColorAdd_UV in GDTF v1.0\n    inheritFrom: 'ColorAdd_UV',\n  },\n  'ColorRGB_W': {\n    // Renamed to ColorAdd_W in GDTF v1.0\n    inheritFrom: 'ColorAdd_W',\n  },\n  'ColorRGB_WW': {\n    // Renamed to ColorAdd_WW in GDTF v1.0\n    inheritFrom: 'ColorAdd_WW',\n  },\n  'ColorRGB_Y': {\n    // Renamed to ColorAdd_Y in GDTF v1.0\n    inheritFrom: 'ColorAdd_Y',\n  },\n  'ColorEffects': {\n    // Renamed to ColorEffects(n) in GDTF v1.0\n    inheritFrom: 'ColorEffects(n)',\n  },\n  'ColorMacro': {\n    // Renamed to ColorMacro(n) in GDTF v1.0\n    inheritFrom: 'ColorMacro(n)',\n  },\n  'Control': {\n    // Renamed to Control(n) in GDTF v1.0\n    inheritFrom: 'Control(n)',\n  },\n  'ControlAutofocus': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlBlackout': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlCalibrationMode': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlColorMode': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlCRIMode': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlDimmerCurve': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlDisplayIntensity': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlDMXInput': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlFanMode': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlFollowSpotMode': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlLamp': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlLampMode': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlPanTiltMode': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlParking': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlReset': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'ControlWhiteCount': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Control(n)',\n  },\n  'CTG': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'CTO',\n  },\n  'Effects': {\n    // Renamed to Effects(n) in GDTF v1.0\n    inheritFrom: 'Effects(n)',\n  },\n  'EffectsFade': {\n    // Renamed to Effects(n)Fade in GDTF v1.0\n    inheritFrom: 'Effects(n)Fade',\n  },\n  'EffectsIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'EffectsMacro': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Effects(n)',\n  },\n  'EffectsPar(n)': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Effects(n)Adjust(m) since GDTF v1.0\n    inheritFrom: 'Effects(n)Adjust(m)',\n  },\n  'EffectsPos': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Effects(n)Pos since GDTF v1.0\n    inheritFrom: 'Effects(n)Pos',\n  },\n  'EffectsPosIndex': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Effects(n)Pos',\n  },\n  'EffectsPosSpin': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Effects(n)PosRotate since GDTF v1.0\n    inheritFrom: 'Effects(n)PosRotate',\n  },\n  'EffectsRate': {\n    // Renamed to Effects(n)Rate in GDTF v1.0\n    inheritFrom: 'Effects(n)Rate',\n  },\n  'EffectsRateIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'EffectsSelectIndex': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Effects(n)',\n  },\n  'EffectsSelectSpin': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Effects(n)',\n  },\n  'EffectsSelectSpinDynamic': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Effects(n)',\n  },\n  'Effects(n)Macro': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'Effects(n)Par(m)': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Effects(n)Adjust(m)',\n  },\n  'Fan': {\n    // Renamed to Fan(n) in GDTF v1.0\n    inheritFrom: 'Fan(n)',\n  },\n  'Focus': {\n    // Renamed to Focus(n) in GDTF v1.0\n    inheritFrom: 'Focus(n)',\n  },\n  'FocusAdjust': {\n    // Renamed to Focus(n)Adjust in GDTF v1.0\n    inheritFrom: 'Focus(n)Adjust',\n  },\n  'FocusDistance': {\n    // Renamed to Focus(n)Distance in GDTF v1.0\n    inheritFrom: 'Focus(n)Distance',\n  },\n  'Fog': {\n    // Renamed to Fog(n) in GDTF v1.0\n    inheritFrom: 'Fog(n)',\n  },\n  'Frost': {\n    // Renamed to Frost(n) in GDTF v1.0\n    inheritFrom: 'Frost(n)',\n  },\n  'FrostHeavy': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Frost(n)',\n  },\n  'FrostLight': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Frost(n)',\n  },\n  'FrostMedium': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Frost(n)',\n  },\n  'FrostMSpeed': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Frost(n)MSpeed since GDTF v1.0\n    inheritFrom: 'Frost(n)MSpeed',\n  },\n  'Gobo(n)Audio': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Gobo(n)WheelAudio since GDTF v0.88\n    inheritFrom: 'Gobo(n)WheelAudio',\n  },\n  'Gobo(n)GoboIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'Gobo(n)GoboShakeIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'Gobo(n)PosIndex': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Gobo(n)Pos',\n  },\n  'Gobo(n)PosRotation': {\n    // Renamed to Gobo(n)PosRotate in GDTF v0.88\n    inheritFrom: 'Gobo(n)PosRotate',\n  },\n  'Gobo(n)PosSpin': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Gobo(n)PosRotate',\n  },\n  'Gobo(n)Random': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    // Officially supported as Gobo(n)WheelRandom since GDTF v0.88\n    inheritFrom: 'Gobo(n)WheelRandom',\n  },\n  'Gobo(n)RandomAudio': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Gobo(n)WheelAudio',\n  },\n  'Gobo(n)Select': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Gobo(n)',\n  },\n  'Gobo(n)SelectIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'Gobo(n)Shake': {\n    // Renamed to Gobo(n)WheelShake in GDTF v0.88\n    inheritFrom: 'Gobo(n)WheelShake',\n  },\n  'Gobo(n)SelectShakeIndex': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Gobo(n)SelectShake',\n  },\n  'Gobo(n)SelectShakeSpin': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'Gobo(n)Spin': {\n    // Renamed to Gobo(n)WheelSpin in GDTF v0.88\n    inheritFrom: 'Gobo(n)WheelSpin',\n  },\n  'GoboWheelMSpeed': {\n    // Renamed to GoboWheel(n)MSpeed in GDTF v1.0\n    inheritFrom: 'GoboWheel(n)MSpeed',\n  },\n  'Haze': {\n    // Renamed to Haze(n) in GDTF v1.0\n    inheritFrom: 'Haze(n)',\n  },\n  'Prism': {\n    // Renamed to Prism(n) in GDTF v0.88\n    inheritFrom: 'Prism(n)',\n  },\n  'PrismPos': {\n    // Renamed to Prism(n)Pos in GDTF v0.88\n    inheritFrom: 'Prism(n)Pos',\n  },\n  'PrismPosIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'PrismPosRotation': {\n    // Renamed to Prism(n)PosRotate in GDTF v0.88\n    inheritFrom: 'Prism(n)PosRotate',\n  },\n  'PrismPrismIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'Prism(n)PosIndex': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Prism(n)Pos',\n  },\n  'Prism(n)PosRotation': {\n    // Renamed to Prism(n)PosRotate in GDTF v0.88\n    inheritFrom: 'Prism(n)PosRotate',\n  },\n  'Prism(n)PosSpin': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Prism(n)PosRotate',\n  },\n  'Prism(n)PrismIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'Prism(n)SelectIndex': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'Prism(n)',\n  },\n  'PrismMSpeed': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    inheritFrom: 'IrisMSpeed',\n  },\n  'Shaper': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'ShaperIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'ShaperPos': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    oflType: 'Rotation',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'ShaperPosIndex': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    oflType: 'Rotation',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'ShaperPosSpin': {\n    // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n    oflType: 'Rotation',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'AngularSpeed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      normalizeAngularSpeedDirection(gdtfCapability);\n    },\n  },\n  'ShaperRotIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'ShaperSelectIndex': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'ShaperSelectSpin': undefined, // From https://gitlab.com/petrvanek/gdtf-libraries/blob/master/gdtf.xsd\n  'Shutter': {\n    // Renamed to Shutter(n) in GDTF v1.0\n    inheritFrom: 'Shutter(n)',\n  },\n  'ShutterStrobe': {\n    // Renamed to Shutter(n)Strobe in GDTF v1.0\n    inheritFrom: 'Shutter(n)Strobe',\n  },\n  'ShutterStrobePulse': {\n    // Renamed to Shutter(n)StrobePulse in GDTF v1.0\n    inheritFrom: 'Shutter(n)StrobePulse',\n  },\n  'ShutterStrobePulseClose': {\n    // Renamed to Shutter(n)StrobePulseClose in GDTF v1.0\n    inheritFrom: 'Shutter(n)StrobePulseClose',\n  },\n  'ShutterStrobePulseOpen': {\n    // Renamed to Shutter(n)StrobePulseOpen in GDTF v1.0\n    inheritFrom: 'Shutter(n)StrobePulseOpen',\n  },\n  'ShutterStrobeRandom': {\n    // Renamed to Shutter(n)StrobeRandom in GDTF v1.0\n    inheritFrom: 'Shutter(n)StrobeRandom',\n  },\n  'ShutterStrobeRandomPulse': {\n    // Renamed to Shutter(n)StrobeRandomPulse in GDTF v1.0\n    inheritFrom: 'Shutter(n)StrobeRandomPulse',\n  },\n  'ShutterStrobeRandomPulseClose': {\n    // Renamed to Shutter(n)StrobeRandomPulseClose in GDTF v1.0\n    inheritFrom: 'Shutter(n)StrobeRandomPulseClose',\n  },\n  'ShutterStrobeRandomPulseOpen': {\n    // Renamed to Shutter(n)StrobeRandomPulseOpen in GDTF v1.0\n    inheritFrom: 'Shutter(n)StrobeRandomPulseOpen',\n  },\n};\n\n/**\n * @param {object} gdtfCapability The enhanced <ChannelSet> XML object.\n * @param {string} primaryColor The color that this capability is most likely.\n * @param {string} secondaryColor The color that this capability is second most likely.\n * @returns {string} Either the primary, or the secondary color.\n */\nfunction guessColorComponentName(gdtfCapability, primaryColor, secondaryColor) {\n  const name = (gdtfCapability._channelFunction._attribute.$.Pretty || '').toLowerCase();\n\n  if (name.includes(secondaryColor.toLowerCase())) {\n    return secondaryColor;\n  }\n\n  if (name.includes(primaryColor.toLowerCase())) {\n    return primaryColor;\n  }\n\n  if (name.includes(secondaryColor.charAt(0).toLowerCase())) {\n    return secondaryColor;\n  }\n\n  return primaryColor;\n}\n\nexport default deprecatedGdtfAttributes;\n"
  },
  {
    "path": "plugins/gdtf/gdtf-attributes.js",
    "content": "import deprecatedGdtfAttributes from './deprecated-gdtf-attributes.js';\nimport {\n  followXmlNodeReference,\n  getRgbColorFromGdtfColor,\n  normalizeAngularSpeedDirection,\n} from './gdtf-helpers.js';\n\n// see https://gdtf-share.com/wiki/GDTF_File_Description#Attribute\nexport const gdtfUnits = {\n  None(value) {\n    return value;\n  },\n  Percent(value) {\n    return `${value * 100}%`;\n  },\n  Length(value) {\n    return `${value}m`;\n  },\n  Mass(value) {\n    return `${value}kg`;\n  },\n  Time(value, otherValue) {\n    if (physicalValuesFulfillCondition(value, otherValue, (number) => Math.abs(number) < 1)) {\n      return `${value * 1000}ms`;\n    }\n\n    return `${value}s`;\n  },\n  Temperature(value) {\n    return `${value}K`;\n  },\n  LuminousIntensity(value) {\n    return `${value}cd`;\n  },\n  Angle(value) {\n    return `${value}deg`;\n  },\n  Force(value) {\n    return `${value}N`;\n  },\n  Frequency(value) {\n    return `${value}Hz`;\n  },\n  Current(value) {\n    return `${value}A`;\n  },\n  Voltage(value) {\n    return `${value}V`;\n  },\n  Power(value) {\n    return `${value}W`;\n  },\n  Energy(value) {\n    return `${value}J`;\n  },\n  Area(value) {\n    return `${value}m2`;\n  },\n  Volume(value) {\n    return `${value}m3`;\n  },\n  Speed(value) {\n    return `${value}m/s`;\n  },\n  Acceleration(value) {\n    return `${value}m/s2`;\n  },\n  AngularSpeed(value, otherValue) {\n    // values are in deg/s\n\n    if (value === 0 && otherValue === null) {\n      return 'stop';\n    }\n\n    return `${value / 360 * 60}rpm`;\n  },\n  AngularAcc(value) {\n    return `${value}deg/s2`;\n  },\n  Wavelength(value) {\n    // it's actually 'WaveLength' in GDTF, but likely to change in the next GDTF version\n    // see https://github.com/OpenLightingProject/open-fixture-library/pull/1084\n    return `${value}nm`;\n  },\n  ColorComponent(value) {\n    // this entity is used as a brightness percentage for\n    // ColorRGBX attributes (X = 1…16) and CTO / CTC / CTB attributes\n    // or as an \"index offset\" for ColorX attributes (X = 1…4) -> handled before\n    return `${value * 100}%`;\n  },\n};\n\n/**\n * @param {number} value1 The first physical value.\n * @param {number | null} value2 The second physical value, or null.\n * @param {(value: number) => boolean} predicate A function returning a boolean.\n * @returns {boolean} True if all provided values fulfill the condition predicate.\n */\nfunction physicalValuesFulfillCondition(value1, value2, predicate) {\n  return predicate(value1) && (value2 === null || predicate(value2));\n}\n\n// see https://gdtf-share.com/wiki/GDTF_File_Description#Appendix_A._Attribute_Definitions\nconst gdtfAttributes = {\n  'AnimationWheel(n)': {\n    // This is the main attribute of the animation wheel's (n) wheel control. Selects slots in the animation wheel. A different channel function sets the angle of the indexed position in the selected slot or the angular speed of its continuous rotation.\n    inheritFrom: 'Gobo(n)',\n  },\n  'AnimationWheel(n)Audio': {\n    // Controls audio-controlled functionality of animation wheel (n).\n    inheritFrom: 'Gobo(n)WheelAudio',\n  },\n  'AnimationWheel(n)Macro': {\n    // Selects predefined effects in animation wheel (n).\n    inheritFrom: 'Gobo(n)WheelRandom',\n  },\n  'AnimationWheel(n)Mode': {\n    // Changes control between selecting, indexing, and rotating the slots of animation wheel (n).\n    oflType: 'Maintenance',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'AnimationWheel(n)Pos': {\n    // Controls angle of indexed rotation of slots in animation wheel. This is the main attribute of animation wheel (n) wheel slot control.\n    inheritFrom: 'Gobo(n)Pos',\n  },\n  'AnimationWheel(n)PosRotate': {\n    // Controls the speed and direction of continuous rotation of slots in animation wheel (n).\n    inheritFrom: 'Gobo(n)PosRotate',\n  },\n  'AnimationWheel(n)PosShake': {\n    // Controls frequency of the shake of slots in animation wheel (n).\n    inheritFrom: 'Gobo(n)PosShake',\n  },\n  'AnimationWheel(n)Random': {\n    // Controls speed of animation wheel (n) random slot selection.\n    inheritFrom: 'Gobo(n)WheelRandom',\n  },\n  'AnimationWheel(n)SelectEffects': {\n    // Selects slots which run effects in animation wheel (n).\n    inheritFrom: 'Gobo(n)SelectEffects',\n  },\n  'AnimationWheel(n)SelectShake': {\n    // Selects slots which shake in animation wheel and controls the frequency of the slots shake within the same channel function.\n    inheritFrom: 'Gobo(n)SelectShake',\n  },\n  'AnimationWheel(n)SelectSpin': {\n    // Selects slots whose rotation is continuous in animation wheel and controls the angular speed of the slot spin within the same channel function\n    inheritFrom: 'Gobo(n)SelectSpin',\n  },\n  'AnimationWheelShortcutMode': {\n    // Defines whether the animation wheel takes the shortest distance between two positions.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'BeamEffectIndexRotateMode': {\n    // Changes mode to control either index or rotation of the beam effects.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'BeamReset': {\n    // Resets the fixture's beam features.\n    oflType: 'Maintenance',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'BeamShaper': undefined, // Activates fixture's beam shaper.\n  'BeamShaperMacro': undefined, // Predefined presets for fixture's beam shaper positions.\n  'BeamShaperPos': undefined, // Indexing of fixture's beam shaper.\n  'BeamShaperPosRotate': undefined, // Continuous rotation of fixture's beam shaper.\n  'BlackoutMode': undefined, // Close the light output under certain conditions (movement correction, gobo movement, etc.).\n  'Blade(n)A': {\n    // 1 of 2 shutters that shape the top/right/bottom/left of the beam.\n    oflType: 'BladeInsertion',\n    oflProperty: 'insertion',\n    defaultPhysicalEntity: 'Percent', // Angle is also common\n    beforePhysicalPropertyHook(capability, gdtfCapability, attributeName) {\n      const positions = ['Top', 'Right', 'Bottom', 'Left'];\n      const bladeNumber = Number.parseInt(attributeName.slice(5), 10);\n      capability.blade = positions[bladeNumber - 1] || bladeNumber;\n    },\n  },\n  'Blade(n)B': {\n    // 2 of 2 shutters that shape the top/right/bottom/left of the beam.\n    inheritFrom: 'Blade(n)A',\n  },\n  'Blade(n)Rot': {\n    // Rotates position of blade(n).\n    inheritFrom: 'Blade(n)A',\n    oflType: 'BladeRotation',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'Blower(n)': undefined, // Fog or hazer‘s blower feature.\n  'ChromaticMode': undefined, // Selects chromatic behavior of the device.\n  'CIE_Brightness': undefined, // Controls the fixture's CIE 1931 color attribute regarding the brightness (Y).\n  'CIE_X': undefined, // Controls the fixture's CIE 1931 color attribute regarding the chromaticity x.\n  'CIE_Y': undefined, // Controls the fixture's CIE 1931 color attribute regarding the chromaticity y.\n  'Color(n)': {\n    // The fixture’s color wheel (n). Selects colors in color wheel (n). This is the main attribute of color wheel’s (n) wheel control.\n    oflType: 'WheelSlot',\n    oflProperty: 'slotNumber',\n    defaultPhysicalEntity: 'None',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      const gdtfSlotNumber = Number.parseInt(gdtfCapability.$.WheelSlotIndex, 10);\n\n      let slotNumberStart = gdtfSlotNumber;\n      let slotNumberEnd = gdtfSlotNumber;\n\n      const physicalFrom = gdtfCapability._physicalFrom;\n      const physicalTo = gdtfCapability._physicalTo;\n\n      if (physicalFrom !== 0 || physicalTo !== 1) {\n        slotNumberStart += physicalFrom;\n        slotNumberEnd += physicalTo;\n      }\n\n      // write back physical values so that they can be assigned to slotNumber or slotNumberStart/slotNumberEnd\n      gdtfCapability._physicalFrom = slotNumberStart;\n      gdtfCapability._physicalTo = slotNumberEnd;\n\n      capability.wheel = gdtfCapability._channelFunction.$.Wheel || 'Unknown';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      const gdtfSlotIndex = Number.parseInt(gdtfCapability.$.WheelSlotIndex, 10) - 1;\n\n      if ('Wheel' in gdtfCapability._channelFunction.$) {\n        const wheelReference = gdtfCapability._channelFunction.$.Wheel;\n        const gdtfWheel = followXmlNodeReference(gdtfCapability._fixture.Wheels[0], wheelReference);\n        const gdtfSlot = gdtfWheel.Slot[gdtfSlotIndex];\n\n        if (gdtfSlot && gdtfCapability.$.Name === gdtfSlot.$.Name) {\n          // clear comment\n          gdtfCapability.$.Name = '';\n        }\n      }\n    },\n  },\n  'Color(n)Mode': {\n    // Changes control between selecting, continuous selection, half selection, random selection, color spinning, etc. in colors of color wheel 1.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'Color(n)WheelAudio': {\n    // Controls audio-controlled functionality of color wheel 1 (since GDTF v0.88)\n    oflType: 'Effect',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Speed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.effectName = gdtfCapability.$.Name;\n      gdtfCapability.$.Name = undefined;\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.soundControlled = true;\n    },\n  },\n  'Color(n)WheelIndex': {\n    // Controls angle of indexed rotation of color wheel 1 (since GDTF v0.88)\n    oflType: 'WheelRotation',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.wheel = gdtfCapability._channelFunction.$.Wheel || 'Unknown';\n    },\n  },\n  'Color(n)WheelRandom': {\n    // Controls speed of color wheel´s 1 random color slot selection. (since GDTF v0.88)\n    inheritFrom: 'Effects(n)',\n  },\n  'Color(n)WheelSpin': {\n    // Controls the speed and direction of continuous rotation of color wheel 1.\n    oflType: 'WheelRotation',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'AngularSpeed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.wheel = gdtfCapability._channelFunction.$.Wheel || 'Unknown';\n      normalizeAngularSpeedDirection(gdtfCapability);\n    },\n  },\n  'ColorAdd_B': {\n    // Controls the intensity of the fixture's blue emitters for direct additive color mixing. (since GDTF v1.0)\n    oflType: 'ColorIntensity',\n    oflProperty: 'brightness',\n    defaultPhysicalEntity: 'ColorComponent',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Blue';\n    },\n  },\n  'ColorAdd_BC': {\n    // Controls the intensity of the fixture's light-blue emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Blue';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.comment = 'Light-Blue';\n    },\n  },\n  'ColorAdd_BM': {\n    // Controls the intensity of the fixture's purple emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Indigo';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.comment = 'Purple';\n    },\n  },\n  'ColorAdd_C': {\n    // Controls the intensity of the fixture's cyan emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Cyan';\n    },\n  },\n  'ColorAdd_CW': {\n    // Controls the intensity of the fixture's cool white emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Cold White';\n    },\n  },\n  'ColorAdd_G': {\n    // Controls the intensity of the fixture's green emitters for direct additive color mixing (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Green';\n    },\n  },\n  'ColorAdd_GC': {\n    // Controls the intensity of the fixture's blue-green emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Blue';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.comment = 'Blue-Green';\n    },\n  },\n  'ColorAdd_GY': {\n    // Controls the intensity of the fixture's lime emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Lime';\n    },\n  },\n  'ColorAdd_M': {\n    // Controls the intensity of the fixture's magenta emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Magenta';\n    },\n  },\n  'ColorAdd_R': {\n    // Controls the intensity of the fixture's red emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Red';\n    },\n  },\n  'ColorAdd_RM': {\n    // Controls the intensity of the fixture's pink emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Magenta';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.comment = 'Pink';\n    },\n  },\n  'ColorAdd_RY': {\n    // Controls the intensity of the fixture's amber emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Amber';\n    },\n  },\n  'ColorAdd_UV': {\n    // Controls the intensity of the fixture's UV emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'UV';\n    },\n  },\n  'ColorAdd_W': {\n    // Controls the intensity of the fixture's white emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'White';\n    },\n  },\n  'ColorAdd_WW': {\n    // Controls the intensity of the fixture's warm white emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Warm White';\n    },\n  },\n  'ColorAdd_Y': {\n    // Controls the intensity of the fixture's yellow emitters for direct additive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.color = 'Yellow';\n    },\n  },\n  'ColorCalibrationMode': {\n    // Sets calibration mode (for example on/off). (since GDTF v1.0)\n    inheritFrom: 'Control(n)',\n  },\n  'ColorConsistency': {\n    // Controls consistent behavior of color. (since GDTF v1.0)\n    inheritFrom: 'Control(n)',\n  },\n  'ColorControl': {\n    // Controls special color related functions. (since GDTF v1.0)\n    oflType: 'Maintenance',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'ColorEffects(n)': {\n    // Selects predefined color effects built into the fixture.\n    inheritFrom: 'Effects(n)',\n  },\n  'ColorMacro(n)': {\n    // Selects predefined colors that are programed in the fixture's firmware.\n    oflType: 'ColorPreset',\n    oflProperty: null,\n    defaultPhysicalEntity: 'ColorComponent',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      // sometimes a workaround to add color information is used: reference a virtual color wheel\n\n      const index = Number.parseInt(gdtfCapability.$.WheelSlotIndex, 10) - 1;\n      if ('Wheel' in gdtfCapability._channelFunction.$) {\n        const wheelReference = gdtfCapability._channelFunction.$.Wheel;\n        const gdtfWheel = followXmlNodeReference(gdtfCapability._fixture.Wheels[0], wheelReference);\n        const gdtfSlot = gdtfWheel.Slot[index];\n\n        if (gdtfSlot) {\n          if (gdtfCapability.$.Name !== gdtfSlot.$.Name) {\n            gdtfCapability.$.Name += ` (${gdtfSlot.$.Name})`;\n          }\n\n          if (gdtfSlot.$.Color) {\n            capability.colors = [getRgbColorFromGdtfColor(gdtfSlot.$.Color)];\n          }\n        }\n      }\n    },\n  },\n  'ColorMixMode': {\n    // Changes control between selecting continuous selection, half selection, random selection, color spinning, etc. in color mixing.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'ColorMixMSpeed': {\n    // Movement speed of the fixture's ColorMix presets.\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'ColorMixReset': {\n    // Resets the fixture's color mixing system.\n    inheritFrom: 'BeamReset',\n  },\n  'ColorModelMode': {\n    // Controls color model (CMY/RGB/HSV..). (since GDTF v1.0)\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'ColorRGB_Blue': {\n    // Controls the fixture's blue attribute for indirect RGB color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n  },\n  'ColorRGB_Cyan': {\n    // Controls the fixture's cyan attribute for indirect CMY color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_C',\n  },\n  'ColorRGB_Green': {\n    // Controls the fixture's green attribute for indirect RGB color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_G',\n  },\n  'ColorRGB_Magenta': {\n    // Controls the fixture's magenta attribute for indirect CMY color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_M',\n  },\n  'ColorRGB_Quality': undefined, // Controls the fixture's quality attribute for indirect color mixing. (since GDTF v1.0)\n  'ColorRGB_Red': {\n    // Controls the fixture's red attribute for indirect RGB color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_R',\n  },\n  'ColorRGB_Yellow': {\n    // Controls the fixture's yellow attribute for indirect CMY color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_Y',\n  },\n  'ColorSettingsReset': {\n    // Resets settings of color control channel. (since GDTF v1.0)\n    inheritFrom: 'BeamReset',\n  },\n  'ColorSub_B': {\n    // Controls the insertion of the fixture's blue filter flag for direct subtractive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_B',\n  },\n  'ColorSub_C': {\n    // Controls the insertion of the fixture's cyan filter flag for direct subtractive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_C',\n  },\n  'ColorSub_G': {\n    // Controls the insertion of the fixture's green filter flag for direct subtractive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_G',\n  },\n  'ColorSub_M': {\n    // Controls the insertion of the fixture's magenta filter flag for direct subtractive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_M',\n  },\n  'ColorSub_R': {\n    // Controls the insertion of the fixture's red filter flag for direct subtractive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_R',\n  },\n  'ColorSub_Y': {\n    // Controls the insertion of the fixture's yellow filter flag for direct subtractive color mixing. (since GDTF v1.0)\n    inheritFrom: 'ColorAdd_Y',\n  },\n  'ColorUniformity': undefined, // Controls behavior of color uniformity. (since GDTF v1.0)\n  'ColorWheelReset': {\n    // Resets the fixture's color wheel.\n    inheritFrom: 'BeamReset',\n  },\n  'ColorWheelSelectMSpeed': {\n    // Movement speed of the fixture's color wheel.\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'ColorWheelShortcutMode': {\n    // Defines whether the color wheel takes the shortest distance between two colors.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'Control(n)': {\n    // Controls the channel of a fixture.\n    oflType: 'Maintenance',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'CRIMode': undefined, // Controls CRI settings of output. (since GDTF v1.0)\n  'CTB': {\n    // Controls the fixture's \"Correct to blue\" wheel or mixing system.\n    inheritFrom: 'CTO',\n  },\n  'CTBReset': {\n    // Resets the fixture's CTB.\n    inheritFrom: 'BeamReset',\n  },\n  'CTC': {\n    // Controls the fixture's \"Correct to color\" wheel or mixing system.\n    inheritFrom: 'CTO',\n  },\n  'CTCReset': {\n    // Resets the fixture's CTC.\n    inheritFrom: 'BeamReset',\n  },\n  'CTO': {\n    // Controls the fixture's \"Correct to orange\" wheel or mixing system.\n    oflType: 'ColorTemperature',\n    oflProperty: 'colorTemperature',\n    defaultPhysicalEntity: 'Temperature', // ColorComponent is also common\n  },\n  'CTOReset': {\n    // Resets the fixture's CTO.\n    inheritFrom: 'BeamReset',\n  },\n  'CustomColor': undefined, // Custom color related functions (save, recall..). (since GDTF v1.0)\n  'CyanMode': {\n    // Controls how Cyan is used within the fixture's cyan CMY-mixing feature.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'Dimmer': {\n    // Controls the intensity of a fixture.\n    oflType: 'Intensity',\n    oflProperty: 'brightness',\n    defaultPhysicalEntity: 'LuminousIntensity',\n  },\n  'DimmerCurve': {\n    // Selects different dimmer curves of the fixture.\n    oflType: 'Maintenance',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'DimmerMode': {\n    // Selects different modes of intensity.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'DisplayIntensity': undefined, // Adjusts intensity of display (since GDTF v1.0)\n  'DMXInput': undefined, // Selects DMX Input (since GDTF v1.0)\n  'Effects(n)': {\n    // Generically predefined macros and effects of a fixture.\n    oflType: 'Effect',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Speed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.effectName = gdtfCapability.$.Name;\n      gdtfCapability.$.Name = undefined;\n    },\n  },\n  'Effects(n)Adjust(m)': {\n    // Controls parameter (m) of effect (n) (since GDTF v1.0)\n    oflType: 'EffectParameter',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'None',\n  },\n  'Effects(n)Fade': {\n    // Snapping or smooth look of running effects.\n    oflType: 'EffectDuration',\n    oflProperty: 'duration',\n    defaultPhysicalEntity: 'Time',\n  },\n  'Effects(n)Pos': {\n    // Controls angle of indexed rotation of slot/effect in effect wheel/macro (n). This is the main attribute of effect wheel/macro (n) slot/effect control. (since GDTF v1.0)\n    oflType: 'Rotation',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'Effects(n)PosRotate': {\n    // Controls speed and direction of slot/effect in effect wheel (n). (since GDTF v1.0)\n    oflType: 'Rotation',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'AngularSpeed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      normalizeAngularSpeedDirection(gdtfCapability);\n    },\n  },\n  'Effects(n)Rate': {\n    // Speed of running effects.\n    oflType: 'EffectSpeed',\n    oflProperty: guessSpeedOrDuration,\n    defaultPhysicalEntity: 'Speed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      if (gdtfCapability._channelFunction._attribute.$.PhysicalUnit === 'Time') {\n        // overwrite capability type\n        capability.type = 'EffectDuration';\n      }\n    },\n  },\n  'EffectsSync': undefined, // Sets offset between running effects and effects 2.\n  'Fan(n)': {\n    // Fog or hazer's Fan feature.\n    oflType: 'Rotation',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'AngularSpeed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      normalizeAngularSpeedDirection(gdtfCapability);\n    },\n  },\n  'Fan(n)Mode': undefined, // Controls fan (n) mode.\n  'Fans': undefined, // Fancontrols a fixture or device.\n  'FixtureCalibrationReset': {\n    // Resets the fixture's calibration.\n    inheritFrom: 'BeamReset',\n  },\n  'FixtureGlobalReset': {\n    // Generally resets the entire fixture.\n    inheritFrom: 'BeamReset',\n  },\n  'Focus(n)': {\n    // Controls the sharpness of the fixture's spot light. Can blur or sharpen the edge of the spot.\n    oflType: 'Focus',\n    oflProperty: 'distance',\n    defaultPhysicalEntity: 'Length',\n  },\n  'Focus(n)Adjust': {\n    // Autofocuses functionality using presets.\n    inheritFrom: 'Focus(n)',\n  },\n  'Focus(n)Distance': {\n    // Autofocuses functionality using distance.\n    inheritFrom: 'Focus(n)',\n  },\n  'FocusMode': {\n    // Changes modes of the fixture’s focus - manual or auto- focus.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'FocusMSpeed': {\n    // Movement speed of the fixture's focus.\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'FocusReset': {\n    // Resets the fixture's focus.\n    inheritFrom: 'BeamReset',\n  },\n  'Fog(n)': {\n    // Fog or hazer's Fog feature.\n    oflType: 'Fog',\n    oflProperty: 'fogOutput',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.fogType = 'Fog';\n    },\n  },\n  'FollowSpotMode': undefined, // Selects follow spot control mode. (since GDTF v1.0)\n  'FrameMSpeed': {\n    // Movement speed of the fixture's shapers.\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'FrameReset': {\n    // Resets the fixture's shapers.\n    inheritFrom: 'BeamReset',\n  },\n  'Frost(n)': {\n    // The ability to soften the fixture's spot light with a frosted lens.\n    oflType: 'Frost',\n    oflProperty: 'frostIntensity',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'Frost(n)MSpeed': {\n    // Movement speed of the fixture's frost (n). (since GDTF v1.0)\n    inheritFrom: 'IrisMSpeed',\n  },\n  'Function': {\n    // Generally controls features of the fixture.\n    oflType: 'Maintenance',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'GlobalMSpeed': {\n    // General speed of fixture's features.\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'Gobo(n)': {\n    // The fixture’s gobo wheel (n). This is the main attribute of gobo wheel’s (n) wheel control. Selects gobos in gobo wheel (n). A different channel function sets the angle of the indexed position in the selected gobo or the angular speed of its continuous rotation.\n    inheritFrom: 'Color(n)',\n  },\n  'Gobo(n)Pos': {\n    // Controls angle of indexed rotation of gobos in gobo wheel (n). This is the main attribute of gobo wheel’s (n) wheel slot control.\n    oflType: 'WheelSlotRotation',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.wheel = gdtfCapability._channelFunction.$.Wheel || 'Unknown';\n    },\n  },\n  'Gobo(n)PosRotate': {\n    // Controls the speed and direction of continuous rotation of gobos in gobo wheel (n).\n    oflType: 'WheelSlotRotation',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'AngularSpeed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.wheel = gdtfCapability._channelFunction.$.Wheel || 'Unknown';\n      normalizeAngularSpeedDirection(gdtfCapability);\n    },\n  },\n  'Gobo(n)PosShake': {\n    // Controls frequency of the shake of gobos in gobo wheel (n).\n    inheritFrom: 'Gobo(n)',\n    oflType: 'WheelShake',\n    oflProperty: 'shakeSpeed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      const gdtfSlotNumber = Number.parseInt(gdtfCapability.$.WheelSlotIndex, 10);\n\n      capability.wheel = gdtfCapability._channelFunction.$.Wheel || 'Unknown';\n      capability.isShaking = 'slot';\n      capability.slotNumber = gdtfSlotNumber;\n    },\n  },\n  'Gobo(n)SelectEffects': {\n    // Selects gobos which run effects in gobo wheel (n). (since GDTF v0.88)\n    inheritFrom: 'Gobo(n)',\n  },\n  'Gobo(n)SelectShake': {\n    // Selects gobos which shake in gobo wheel (n) and controls the frequency of the gobo’s shake within the same channel function. (since GDTF v0.88)\n    inheritFrom: 'Gobo(n)WheelShake',\n  },\n  'Gobo(n)SelectSpin': {\n    // Selects gobos whose rotation is continuous in gobo wheel (n) and controls the angular speed of the gobo’s spin within the same channel function. (since GDTF v0.88)\n    inheritFrom: 'Gobo(n)',\n  },\n  'Gobo(n)WheelAudio': {\n    // Controls audio-controlled functionality of gobo wheel (n). (since GDTF v0.88)\n    oflType: 'Effect',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Speed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.effectName = gdtfCapability.$.Name;\n      gdtfCapability.$.Name = undefined;\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.soundControlled = true;\n    },\n  },\n  'Gobo(n)WheelIndex': {\n    // Controls angle of indexed rotation of gobo wheel (n). (since GDTF v0.88)\n    inheritFrom: 'Gobo(n)',\n  },\n  'Gobo(n)WheelMode': {\n    // Changes control between selecting, indexing, and rotating the gobos of gobo wheel (n).\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'Gobo(n)WheelRandom': {\n    // Controls speed of gobo wheel´s (n) random gobo slot selection. (since GDTF v0.88)\n    oflType: 'Effect',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Speed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.effectName = gdtfCapability.$.Name;\n      gdtfCapability.$.Name = undefined;\n    },\n  },\n  'Gobo(n)WheelShake': {\n    // Controls frequency of the shake of gobo wheel (n).\n    inheritFrom: 'Gobo(n)',\n    oflType: 'WheelShake',\n    oflProperty: 'shakeSpeed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      const gdtfSlotNumber = Number.parseInt(gdtfCapability.$.WheelSlotIndex, 10);\n\n      capability.wheel = gdtfCapability._channelFunction.$.Wheel || 'Unknown';\n      capability.slotNumber = gdtfSlotNumber;\n    },\n  },\n  'Gobo(n)WheelSpin': {\n    // Controls the speed and direction of continuous rotation of gobo wheel (n).\n    oflType: 'WheelRotation',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'AngularSpeed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.wheel = gdtfCapability._channelFunction.$.Wheel || 'Unknown';\n      normalizeAngularSpeedDirection(gdtfCapability);\n    },\n  },\n  'GoboWheel(n)MSpeed': {\n    // Movement speed of the fixture's gobo wheel.\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'GoboWheelReset': {\n    // Resets the fixture's gobo wheel.\n    inheritFrom: 'BeamReset',\n  },\n  'Haze(n)': {\n    // Fog or hazer's haze feature.\n    oflType: 'Fog',\n    oflProperty: 'fogOutput',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.fogType = 'Haze';\n    },\n  },\n  'HSB_Brightness': undefined, // Controls the fixture's color attribute regarding the brightness.\n  'HSB_Hue': undefined, // Controls the fixture's color attribute regarding the hue.\n  'HSB_Quality': undefined, // Controls the fixture's color attribute regarding the quality.\n  'HSB_Saturation': undefined, // Controls the fixture's color attribute regarding the saturation.\n  'IntensityMSpeed': {\n    // Movement speed of the fixture's intensity.\n    oflType: 'Speed',\n    oflProperty: guessSpeedOrDuration,\n    defaultPhysicalEntity: 'Speed',\n  },\n  'IntensityReset': {\n    // Resets the fixture's intensity.\n    inheritFrom: 'BeamReset',\n  },\n  'Iris': {\n    // Controls the diameter of the fixture's beam.\n    oflType: 'Iris',\n    oflProperty: 'openPercent',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'IrisMode': {\n    // Changes modes of the fixture’s iris - linear, strobe, pulse.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'IrisMSpeed': {\n    // Movement speed of the fixture's iris.\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'IrisPulseClose': {\n    // Sets speed of iris‘s closing pulse.\n    oflType: 'IrisEffect',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.effectName = 'RampDown';\n    },\n  },\n  'IrisPulseOpen': {\n    // Sets speed of iris‘s opening pulse.\n    oflType: 'IrisEffect',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.effectName = 'RampUp';\n    },\n  },\n  'IrisReset': {\n    // Resets the fixture's iris.\n    inheritFrom: 'BeamReset',\n  },\n  'IrisStrobe': {\n    // Sets speed of the iris’s strobe feature.\n    oflType: 'IrisEffect',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.effectName = 'Strobe';\n    },\n  },\n  'IrisStrobeRandom': {\n    // Sets speed of the iris's random movement. (since GDTF v1.0)\n    inheritFrom: 'IrisStrobe',\n    afterPhysicalPropertyHook(capability) {\n      capability.randomTiming = true;\n    },\n  },\n  'LampControl': {\n    // Controls the fixture's lamp on/lamp off feature.\n    oflType: 'Maintenance',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'LampPowerMode': {\n    // Controls the energy consumption of the lamp.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'LEDFrequency': undefined, // Controls LED frequency. (since GDTF v1.0)\n  'LEDZoneMode': undefined, // Changes zones of LEDs. (since GDTF v1.0)\n  'MagentaMode': {\n    // Controls how Cyan is used within the fixture's magenta CMY-mixing.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'MediaContent': undefined, // Selects the content slot of in the selected media folder (e.g. of a media server). (since GDTF v1.0)\n  'MediaFolder': undefined, // Selects the media folder of a device (e.g., a media server). (since GDTF v1.0)\n  'NoFeature': {\n    // Ranges without a functionality.\n    oflType: 'NoFunction',\n    oflProperty: null,\n  },\n  'Pan': {\n    // Controls the fixture's sideward movement (horizontal axis).\n    oflType: 'Pan',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'PanMode': {\n    // Selects fixture's pan mode. Selects between a limited pan range (e.g. -270 to 270) or a continuous pan range.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'PanReset': {\n    // Resets the fixture's pan.\n    inheritFrom: 'BeamReset',\n  },\n  'PanTiltMode': undefined, // Selects fixture's pan/tilt mode. Selects between a limited pan/tilt range or a continuous pan/tilt range. (since GDTF v1.0)\n  'PixelMode': undefined, // Controls behavior of LED pixels. (since GDTF v1.0)\n  'Playmode': undefined, // Selects the playmode of a device (e.g., a media server). (since GDTF v1.0)\n  'PositionEffect': {\n    // Selects the predefined position effects that are built into the fixture.\n    inheritFrom: 'Effects(n)',\n  },\n  'PositionEffectFade': {\n    // Snaps or smooth fades with timing in running predefined position effects.\n    inheritFrom: 'Effects(n)Fade',\n  },\n  'PositionEffectRate': {\n    // Controls the speed of the predefined position effects that are built into the fixture.\n    inheritFrom: 'Effects(n)Rate',\n  },\n  'PositionModes': {\n    // Selects the fixture's position mode.\n    // TODO: Is this a typo in the GDTF wiki / schema and it should be \"PositionMode\"?\n    oflType: 'Maintenance',\n    oflProperty: 'parameter',\n    defaultPhysicalEntity: 'Percent',\n  },\n  'PositionMSpeed': {\n    // Movement speed of the fixture's pan/tilt.\n    inheritFrom: 'IntensityMSpeed',\n    oflType: 'PanTiltSpeed',\n  },\n  'PositionReset': {\n    // Resets the fixture's pan/tilt.\n    inheritFrom: 'BeamReset',\n  },\n  'Prism(n)': {\n    // The fixture’s prism wheel (n). Selects prisms in prism wheel (n). A different channel function sets the angle of the indexed position in the selected prism or the angular speed of its continuous rotation. This is the main attribute of prism wheel’s (n) wheel control.\n    oflType: 'Prism',\n    oflProperty: null,\n    defaultPhysicalEntity: 'None',\n  },\n  'Prism(n)Macro': {\n    // Macro functions of prism wheel (n).\n    inheritFrom: 'Effects(n)',\n  },\n  'Prism(n)MSpeed': {\n    // Movement speed of the fixture's prism wheel (n).\n    inheritFrom: 'IntensityMSpeed',\n  },\n  'Prism(n)Pos': {\n    // Controls angle of indexed rotation of prisms in prism wheel (n). This is the main attribute of prism wheel’s 1 wheel slot control.\n    oflType: 'PrismRotation',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'Prism(n)PosRotate': {\n    // Controls the speed and direction of continuous rotation of prisms in prism wheel (n).\n    oflType: 'PrismRotation',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'AngularSpeed',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      normalizeAngularSpeedDirection(gdtfCapability);\n    },\n  },\n  'Prism(n)SelectSpin': {\n    // Selects prisms whose rotation is continuous in prism wheel (n) and controls the angular speed of the prism’s spin within the same channel function. (since GDTF v0.88)\n    inheritFrom: 'Prism(n)PosRotate',\n  },\n  'ReflectorAdjust': undefined, // Movement speed of the fixture's frost.\n  'ShaperMacros': {\n    // Predefined presets for shaper positions.\n    inheritFrom: 'Effects(n)',\n  },\n  'ShaperMacrosSpeed': {\n    // Speed of predefined effects on shapers,\n    inheritFrom: 'Effects(n)Rate',\n  },\n  'ShaperRot': {\n    // Rotates position of blade assembly.\n    oflType: 'BladeSystemRotation',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'Shutter(n)': {\n    // Controls the fixture´s mechanical or electronical shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: null,\n    defaultPhysicalEntity: 'Frequency', // although that makes little sense since 0 means closed and 1 means open\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      const physicalFrom = gdtfCapability._physicalFrom;\n      const physicalTo = gdtfCapability._physicalTo;\n\n      if (physicalFrom === 0 && physicalTo === 0) {\n        capability.shutterEffect = 'Closed';\n      }\n      else if (physicalFrom === 1 && physicalTo === 1) {\n        capability.shutterEffect = 'Open';\n      }\n      else {\n        capability.helpWanted = `What does physical value ${physicalFrom}…${physicalTo} mean?`;\n      }\n    },\n  },\n  'Shutter(n)Strobe': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical strobe shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.shutterEffect = 'Strobe';\n    },\n  },\n  'Shutter(n)StrobeEffect': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical shutter effect feature.\n    inheritFrom: 'Shutter(n)Strobe',\n  },\n  'Shutter(n)StrobePulse': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical pulse shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.shutterEffect = 'Pulse';\n    },\n  },\n  'Shutter(n)StrobePulseClose': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical closing pulse shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.shutterEffect = 'RampDown';\n    },\n  },\n  'Shutter(n)StrobePulseOpen': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical opening pulse shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.shutterEffect = 'RampUp';\n    },\n  },\n  'Shutter(n)StrobeRandom': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical random strobe shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.shutterEffect = 'Strobe';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.randomTiming = true;\n    },\n  },\n  'Shutter(n)StrobeRandomPulse': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical random pulse shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.shutterEffect = 'Pulse';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.randomTiming = true;\n    },\n  },\n  'Shutter(n)StrobeRandomPulseClose': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical random closing pulse shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.shutterEffect = 'RampDown';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.randomTiming = true;\n    },\n  },\n  'Shutter(n)StrobeRandomPulseOpen': {\n    // Controls the frequency/speed of the fixture´s mechanical or electronical random opening pulse shutter feature.\n    oflType: 'ShutterStrobe',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n    beforePhysicalPropertyHook(capability, gdtfCapability) {\n      capability.shutterEffect = 'RampUp';\n    },\n    afterPhysicalPropertyHook(capability, gdtfCapability) {\n      capability.randomTiming = true;\n    },\n  },\n  'ShutterReset': {\n    // Resets the fixture's shutter.\n    inheritFrom: 'BeamReset',\n  },\n  'StrobeDuration': {\n    // Controls the length of a strobe flash.\n    oflType: 'StrobeDuration',\n    oflProperty: 'duration',\n    defaultPhysicalEntity: 'Time',\n  },\n  'StrobeMode': {\n    // Changes strobe style - strobe, pulse, random strobe, etc. - of the shutter attribute.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'StrobeRate': {\n    // Controls the time between strobe flashes.\n    oflType: 'StrobeSpeed',\n    oflProperty: 'speed',\n    defaultPhysicalEntity: 'Frequency',\n  },\n  'Tilt': {\n    // Controls the fixture's upward and the downward movement (vertical axis).\n    oflType: 'Tilt',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'TiltMode': {\n    // Selects fixture's pan mode. Selects between a limited tilt range (e.g. -130 to 130) or a continuous tilt range.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'TiltReset': {\n    // Resets the fixture's tilt.\n    inheritFrom: 'BeamReset',\n  },\n  'UVStability': undefined, // Settings for UV stability color behavior. (since GDTF v1.0)\n  'Video': undefined, // Controls video features.\n  'VideoCamera(n)': undefined, // Selects the video camera(n). (since GDTF v1.0)\n  'VideoEffect(n)Parameter(m)': undefined, // Controls parameter (m) of VideoEffect(n)Type. (since GDTF v1.0)\n  'VideoEffect(n)Type': undefined, // Selects dedicated effects which are used for media. (since GDTF v1.0)\n  'VideoScale(n)_All': undefined, // Scales the media content or video object along all three axes. (since GDTF v1.0)\n  'VideoScale(n)_X': undefined, // Scales the media content or video object along the x-axis. (since GDTF v1.0)\n  'VideoScale(n)_Y': undefined, // Scales the media content or video object along the y-axis. (since GDTF v1.0)\n  'VideoScale(n)_Z': undefined, // Scales the media content or video object along the z-axis. (since GDTF v1.0)\n  'WavelengthCorrection': undefined, // Settings for WaveLength corrections of colors. (since GDTF v1.0)\n  'WhiteCount': undefined, // Controls if White LED is proportionally added to RGB. (since GDTF v1.0)\n  'XYZ_X': undefined, // Defines a fixture’s x-coordinate within an XYZ coordinate system.\n  'XYZ_Y': undefined, // Defines a fixture’s y-coordinate within an XYZ coordinate system.\n  'XYZ_Z': undefined, // Defines a fixture‘s z-coordinate within an XYZ coordinate system.\n  'YellowMode': {\n    // Controls how Cyan is used within the fixture's yellow CMY-mixing feature.\n    inheritFrom: 'AnimationWheel(n)Mode',\n  },\n  'Zoom': {\n    // Controls the spread of the fixture's beam/spot. (since GDTF v1.0)\n    oflType: 'Zoom',\n    oflProperty: 'angle',\n    defaultPhysicalEntity: 'Angle',\n  },\n  'ZoomMode': undefined, // Changes modes of the fixture´s zoom. (since GDTF v1.0)\n  'ZoomModeBeam': undefined, // Selects beam mode of zoom. (since GDTF v1.0)\n  'ZoomModeSpot': undefined, // Selects spot mode of zoom. (since GDTF v1.0)\n  'ZoomMSpeed': {\n    // Movement speed of the fixture's zoom. (since GDTF v1.0)\n    inheritFrom: 'IrisMSpeed',\n  },\n  'ZoomReset': {\n    // Resets the fixture's zoom.\n    inheritFrom: 'BeamReset',\n  },\n};\n\n/**\n * @param {object} gdtfCapability The enhanced <ChannelSet> XML object.\n * @returns {'speed' | 'duration'} The OFL property to use for this capability.\n */\nfunction guessSpeedOrDuration(gdtfCapability) {\n  return gdtfCapability._channelFunction._attribute.$.PhysicalUnit === 'Time' ? 'duration' : 'speed';\n}\n\nexport default {\n  ...deprecatedGdtfAttributes,\n  ...gdtfAttributes,\n};\n"
  },
  {
    "path": "plugins/gdtf/gdtf-helpers.js",
    "content": "/**\n * @param {object} startNode The XML object the reference should be resolved against.\n * @param {string} nodeReference A string of the form \"Name.Name.Name…\", see https://gdtf-share.com/wiki/GDTF_File_Description#attrType-node\n * @returns {object | null} The referenced XML node object, or null if it could not be found.\n */\nexport function followXmlNodeReference(startNode, nodeReference) {\n  if (!startNode || !nodeReference) {\n    return null;\n  }\n\n  const nameParts = nodeReference.split('.');\n  let currentNode = startNode;\n\n  for (const nameAttribute of nameParts) {\n    const nodeWithNameAttribute = getChildNodes(currentNode).find(\n      (node) => '$' in node && node.$.Name === nameAttribute,\n    );\n\n    if (nodeWithNameAttribute) {\n      currentNode = nodeWithNameAttribute;\n    }\n    else {\n      return null;\n    }\n  }\n\n  return currentNode;\n\n  /**\n   * @param {object} node The XML object.\n   * @returns {object[]} The XML objects of this node's child nodes.\n   */\n  function getChildNodes(node) {\n    return Object.entries(node).flatMap(\n      ([tagName, nodes]) => (tagName === '$' ? [] : nodes),\n    );\n  }\n}\n\n/**\n * Convert from CIE color representation xyY 1931 to RGB.\n * See https://wolfcrow.com/blog/what-is-the-difference-between-cie-lab-cie-rgb-cie-xyy-and-cie-xyz/\n * @param {string} gdtfColorString A string in the form \"0.3127, 0.3290, 100.0\", see https://gdtf-share.com/wiki/GDTF_File_Description#attrType-colorCIE\n * @returns {string} The RGB hex code string in the form \"#rrggbb\".\n */\nexport function getRgbColorFromGdtfColor(gdtfColorString) {\n  /* eslint-disable camelcase, @stylistic/space-in-parens, unicorn/no-zero-fractions */\n\n  // functions ported from https://github.com/njsmith/colorspacious\n  const xyY_to_XYZ = ([x, y, Y]) => {\n    const X = Y / y * x;\n    const Z = Y / y * (1 - x - y);\n    return [X, Y, Z];\n  };\n  const XYZ1_to_XYZ100 = (XYZ1) => XYZ1.map((c) => c * 100);\n  const XYZ100_to_sRGB1_linear = ([X, Y, Z]) => {\n    const R = ( 3.2406 * X / 100) + (-1.5372 * Y / 100) + (-0.4986 * Z / 100);\n    const G = (-0.9689 * X / 100) + ( 1.8758 * Y / 100) + ( 0.0415 * Z / 100);\n    const B = ( 0.0557 * X / 100) + (-0.2040 * Y / 100) + ( 1.0570 * Z / 100);\n    return [R, G, B];\n  };\n  const sRGB1_linear_to_sRGB1 = (RGB_linear) => RGB_linear.map((c) => {\n    if (c <= 0.003_130_8) {\n      return 12.92 * c;\n    }\n\n    const a = 0.055;\n\n    return ((1 + a) * Math.pow(c, 1 / 2.4)) - a;\n  });\n  const sRGB1_to_sRGB255 = (RGB1) => RGB1.map((c) => c * 255);\n\n  // parse starting values as array\n  const [x, y, Y] = gdtfColorString.split(/\\s*,\\s*/).map(\n    (colorComponent) => Number.parseFloat(colorComponent),\n  );\n\n  // ported from https://gitlab.com/petrvanek/gdtf-libraries/blob/e3194638c552321ad06af630ba83f49dcf5b0016/gdtf2json.py#L10-25\n  const RGB = sRGB1_to_sRGB255(sRGB1_linear_to_sRGB1(XYZ100_to_sRGB1_linear(XYZ1_to_XYZ100(xyY_to_XYZ([x, y, Y])))));\n\n  let r, g, b;\n  if (Y > 1) {\n    [r, g, b] = RGB.map((c) => (c > 0 ? c / 255 : 0));\n  }\n  else {\n    [r, g, b] = RGB;\n  }\n\n  let count = 0;\n  while (Math.max(r, g, b) < 127 && count < 5) {\n    r *= 2;\n    g *= 2;\n    b *= 2;\n    count++;\n  }\n\n  // clip to integers in range 0…255\n  [r, g, b] = [r, g, b].map((c) => Math.floor(Math.min(255, Math.max(0, c || 0))));\n\n  return `#${getHexComponent(r)}${getHexComponent(g)}${getHexComponent(b)}`;\n\n  /* eslint-enable camelcase, @stylistic/space-in-parens, unicorn/no-zero-fractions */\n\n  /**\n   * @param {number} componentValue The red / green /blue component value in the range 0…255.\n   * @returns {string} The component value encoded as a two-digit hex number.\n   */\n  function getHexComponent(componentValue) {\n    const hex = componentValue.toString(16);\n    return hex.length === 1 ? `0${hex}` : hex;\n  }\n}\n\n/**\n * @param {object} gdtfCapability The enhanced <ChannelSet> XML object.\n */\nexport function normalizeAngularSpeedDirection(gdtfCapability) {\n  if (/CCW|counter[\\s-]*clockwise/.test(gdtfCapability.$.Name)) {\n    gdtfCapability._physicalFrom = -Math.abs(gdtfCapability._physicalFrom);\n    gdtfCapability._physicalTo = -Math.abs(gdtfCapability._physicalTo);\n  }\n  else if (/CW|clockwise/.test(gdtfCapability.$.Name)) {\n    gdtfCapability._physicalFrom = Math.abs(gdtfCapability._physicalFrom);\n    gdtfCapability._physicalTo = Math.abs(gdtfCapability._physicalTo);\n  }\n}\n"
  },
  {
    "path": "plugins/gdtf/import.js",
    "content": "import JSZip from 'jszip';\nimport xml2js from 'xml2js';\nimport importJson from '../../lib/import-json.js';\nimport CoarseChannel from '../../lib/model/CoarseChannel.js';\nimport { scaleDmxRangeIndividually, scaleDmxValue } from '../../lib/scale-dmx-values.js';\nimport gdtfAttributes, { gdtfUnits } from './gdtf-attributes.js';\nimport { followXmlNodeReference, getRgbColorFromGdtfColor } from './gdtf-helpers.js';\n\nexport const version = '0.2.0';\n\n/**\n * @typedef {object} Relation\n * @property {number} modeIndex The zero-based index of the mode this relation applies to.\n * @property {object} masterGdtfChannel The GDTF channel that triggers switching.\n * @property {string} switchingChannelName The name of the switching channel (containing multiple default channels).\n * @property {object} followerGdtfChannel The GDTF channel that is switched by the master.\n * @property {[number, Resolution]} dmxFrom The DMX value and DMX resolution of the start of the DMX range triggering this relation.\n * @property {[number, Resolution]} dmxTo The DMX value and DMX resolution of the end of the DMX range triggering this relation.\n */\n\n/**\n * @param {Buffer} buffer The imported file.\n * @param {string} filename The imported file's name.\n * @param {string} authorName The importer's name.\n * @returns {Promise<object, Error>} A Promise resolving to an out object\n */\nexport async function importFixtures(buffer, filename, authorName) {\n  const fixture = {\n    $schema: 'https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json',\n  };\n\n  const warnings = [];\n\n  const xml = await getGdtfXml(buffer, filename);\n\n  const gdtfFixture = xml.GDTF.FixtureType[0];\n  fixture.name = gdtfFixture.$.Name;\n  fixture.shortName = gdtfFixture.$.ShortName;\n\n  const manufacturerKey = slugify(gdtfFixture.$.Manufacturer);\n  const fixtureKey = `${manufacturerKey}/${slugify(fixture.name)}`;\n\n  const manufacturers = await importJson('../../fixtures/manufacturers.json', import.meta.url);\n\n  let manufacturer;\n  if (manufacturerKey in manufacturers) {\n    manufacturer = manufacturers[manufacturerKey];\n  }\n  else {\n    manufacturer = {\n      name: gdtfFixture.$.Manufacturer,\n    };\n    warnings.push('Please add manufacturer URL.');\n  }\n\n  fixture.categories = ['Other']; // TODO: can we find out categories?\n  warnings.push('Please add fixture categories.');\n\n  const timestamp = new Date().toISOString().replace(/T.*/, '');\n  const [createDate, lastModifyDate] = getRevisionDates();\n\n  fixture.meta = {\n    authors: [authorName],\n    createDate: getIsoDateFromGdtfDate(createDate, timestamp),\n    lastModifyDate: getIsoDateFromGdtfDate(lastModifyDate, timestamp),\n    importPlugin: {\n      plugin: 'gdtf',\n      date: timestamp,\n      comment: `GDTF v${xml.GDTF.$.DataVersion} fixture type ID: ${gdtfFixture.$.FixtureTypeID}`,\n    },\n  };\n\n  fixture.comment = getFixtureComment();\n\n  warnings.push('Please add relevant links to the fixture.');\n\n  addRdmInfo();\n\n  warnings.push('Please add physical data to the fixture.');\n\n  fixture.matrix = {};\n\n  addWheels();\n\n  autoGenerateGdtfNameAttributes();\n  const switchingChannelRelations = splitSwitchingChannels();\n\n  addChannels();\n  addModes();\n\n  linkSwitchingChannels();\n\n  cleanUpFixture(fixture, warnings);\n\n  return {\n    manufacturers: {\n      [manufacturerKey]: manufacturer,\n    },\n    fixtures: {\n      [fixtureKey]: fixture,\n    },\n    warnings: {\n      [fixtureKey]: warnings,\n    },\n  };\n\n  /**\n   * @returns {[string | undefined, string | undefined]} An array with the earliest and latest revision dates of the GDTF fixture, if they are defined in <Revision> tag.\n   */\n  function getRevisionDates() {\n    if (!gdtfFixture.Revisions?.[0]?.Revision) {\n      return [undefined, undefined];\n    }\n\n    const revisions = gdtfFixture.Revisions[0].Revision;\n    const earliestRevision = revisions[0];\n    const latestRevision = revisions.at(-1);\n\n    return [earliestRevision.$.Date, latestRevision.$.Date];\n  }\n\n  /**\n   * @returns {string | undefined} The comment to add to the fixture.\n   */\n  function getFixtureComment() {\n    const { Name, LongName, Manufacturer, Description } = gdtfFixture.$;\n\n    const includeLongName = (LongName && LongName !== Name);\n    const includeDescription = (Description && Description !== `${Manufacturer} ${Name}`);\n\n    if (includeLongName && includeDescription) {\n      return `${LongName}: ${Description}`;\n    }\n\n    if (includeLongName) {\n      return LongName;\n    }\n\n    if (includeDescription) {\n      return Description;\n    }\n\n    return undefined;\n  }\n\n  /**\n   * Adds an RDM section to the OFL fixture and manufacturer if applicable.\n   */\n  function addRdmInfo() {\n    if (!('Protocols' in gdtfFixture) || gdtfFixture.Protocols[0] === '' || !('FTRDM' in gdtfFixture.Protocols[0] || 'RDM' in gdtfFixture.Protocols[0])) {\n      return;\n    }\n\n    const rdmData = (gdtfFixture.Protocols[0].FTRDM || gdtfFixture.Protocols[0].RDM)[0];\n    const softwareVersion = getLatestSoftwareVersion();\n\n    manufacturer.rdmId = Number.parseInt(rdmData.$.ManufacturerID, 16);\n    fixture.rdm = {\n      modelId: Number.parseInt(rdmData.$.DeviceModelID, 16),\n      softwareVersion: softwareVersion.name,\n    };\n\n    for (const personality of softwareVersion.personalities) {\n      const index = Number.parseInt(personality.$.Value.replace('0x', ''), 16);\n      const mode = followXmlNodeReference(gdtfFixture.DMXModes[0].DMXMode, personality.$.DMXMode);\n      mode._oflRdmPersonalityIndex = index;\n    }\n\n    /**\n     * @returns {object} Name and DMX personalities of the latest RDM software version (both may be undefined).\n     */\n    function getLatestSoftwareVersion() {\n      let maxSoftwareVersion = undefined;\n\n      for (const rdmVersion of rdmData.SoftwareVersionID || []) {\n        if (!maxSoftwareVersion || rdmVersion.$.Value > maxSoftwareVersion.$.Value) {\n          maxSoftwareVersion = rdmVersion;\n        }\n      }\n\n      if (maxSoftwareVersion) {\n        return {\n          name: maxSoftwareVersion.$.Value,\n          personalities: maxSoftwareVersion.DMXPersonality,\n        };\n      }\n\n      return {\n        name: rdmData.$.SoftwareVersionID,\n        personalities: [],\n      };\n    }\n  }\n\n  /**\n   * Adds wheels to the OFL fixture (if there are any).\n   */\n  function addWheels() {\n    if (!('Wheels' in gdtfFixture)) {\n      return;\n    }\n\n    const gdtfWheels = (gdtfFixture.Wheels[0].Wheel || []).filter(\n      (wheel) => wheel.$.Name !== 'ColorMacro',\n    );\n\n    if (gdtfWheels.length === 0) {\n      return;\n    }\n\n    fixture.wheels = {};\n\n    for (const gdtfWheel of gdtfWheels) {\n      fixture.wheels[gdtfWheel.$.Name] = {\n        slots: (gdtfWheel.Slot || []).map((gdtfSlot) => {\n          const name = gdtfSlot.$.Name;\n\n          const slot = {\n            type: 'Unknown',\n          };\n\n          if (name === 'Open') {\n            slot.type = 'Open';\n          }\n          else if (name === 'Closed') {\n            slot.type = 'Closed';\n          }\n          else if ('Color' in gdtfSlot.$) {\n            slot.type = 'Color';\n            slot.name = name;\n            slot.colors = [getRgbColorFromGdtfColor(gdtfSlot.$.Color)];\n          }\n          else if ('Facet' in gdtfSlot) {\n            slot.type = 'Prism';\n            slot.name = name;\n            slot.facets = gdtfSlot.Facet.length;\n          }\n          else if (name.startsWith('Gobo') || gdtfWheel.$.Name.startsWith('Gobo')) {\n            slot.type = 'Gobo';\n            slot.name = name;\n          }\n          else {\n            slot.name = name;\n          }\n\n          return slot;\n        }),\n      };\n    }\n  }\n\n  /**\n   * Autmatically generates `Name` attributes for GDTF's `<DMXChannel>`,\n   * `<LogicalChannel>` and `<ChannelFunction>` elements if they are not\n   * already defined.\n   */\n  function autoGenerateGdtfNameAttributes() {\n    for (const gdtfMode of gdtfFixture.DMXModes[0].DMXMode) {\n      // add default Name attributes, so that the references work later\n      for (const gdtfChannel of gdtfMode.DMXChannels[0].DMXChannel) {\n        // auto-generate <DMXChannel> Name attribute\n        const geometry = gdtfChannel.$.Geometry.split('.').pop();\n        gdtfChannel.$.Name = `${geometry}_${gdtfChannel.LogicalChannel[0].$.Attribute}`;\n\n        for (const gdtfLogicalChannel of gdtfChannel.LogicalChannel) {\n          // auto-generate <LogicalChannel> Name attribute\n          gdtfLogicalChannel.$.Name = gdtfLogicalChannel.$.Attribute;\n\n          for (const [channelFunctionIndex, gdtfChannelFunction] of gdtfLogicalChannel.ChannelFunction.entries()) {\n            // auto-generate <ChannelFunction> Name attribute if not already defined\n            if (!('Name' in gdtfChannelFunction.$)) {\n              gdtfChannelFunction.$.Name = `${gdtfChannelFunction.$.Attribute} ${channelFunctionIndex + 1}`;\n            }\n          }\n        }\n      }\n    }\n  }\n\n  /**\n   * @returns {Relation[]} An array of relations.\n   */\n  function splitSwitchingChannels() {\n    let relations = getModeMasterRelations();\n\n    if (relations.length === 0) {\n      relations = getLegacyRelations();\n    }\n\n    for (const relation of relations) {\n      const followerChannel = relation.followerGdtfChannel;\n\n      // if channel was already split, skip splitting it again, else\n      // split channel such that followerChannelFunction is the only child\n      if (followerChannel.LogicalChannel[0].ChannelFunction.length > 1) {\n        const channelCopy = structuredClone(followerChannel);\n        channelCopy.$.Name += '_OflSplit';\n        relation.followerGdtfChannel = channelCopy;\n\n        // remove followerChannelFunction from followerChannel and all others from the copy\n        const channelFunctionIndex = followerChannel.LogicalChannel[0].ChannelFunction.indexOf(relation.followerChannelFunction);\n        followerChannel.LogicalChannel[0].ChannelFunction.splice(channelFunctionIndex, 1);\n        channelCopy.LogicalChannel[0].ChannelFunction = [\n          channelCopy.LogicalChannel[0].ChannelFunction[channelFunctionIndex],\n        ];\n\n        // insert channelCopy before the followerChannel\n        const gdtfMode = gdtfFixture.DMXModes[0].DMXMode[relation.modeIndex];\n        const channelIndex = gdtfMode.DMXChannels[0].DMXChannel.indexOf(followerChannel);\n        gdtfMode.DMXChannels[0].DMXChannel.splice(channelIndex, 0, channelCopy);\n      }\n\n      delete relation.followerChannelFunction;\n    }\n\n    return relations;\n\n    /**\n     * Parses <ChannelFunction ModeMaster=\"…\">'s relation data.\n     * This way of specifying relations was added in GDTF v0.88.\n     * @returns {Relation[]} An array of relations, may be empty.\n     */\n    function getModeMasterRelations() {\n      return gdtfFixture.DMXModes[0].DMXMode.flatMap((gdtfMode, modeIndex) => {\n        return gdtfMode.DMXChannels[0].DMXChannel.flatMap((gdtfDmxChannel) => {\n          return gdtfDmxChannel.LogicalChannel.flatMap((gdtfLogicalChannel) => {\n            return gdtfLogicalChannel.ChannelFunction.flatMap((gdtfChannelFunction) => {\n              if (!('ModeMaster' in gdtfChannelFunction.$)) {\n                return [];\n              }\n\n              const masterChannel = followXmlNodeReference(gdtfMode.DMXChannels[0], gdtfChannelFunction.$.ModeMaster.split('.')[0]);\n\n              const dmxFrom = getDmxValueWithResolutionFromGdtfDmxValue(gdtfChannelFunction.$.ModeFrom, 0);\n              const maxDmxValue = Math.pow(256, dmxFrom[1]) - 1;\n              const dmxTo = getDmxValueWithResolutionFromGdtfDmxValue(gdtfChannelFunction.$.ModeTo, maxDmxValue, dmxFrom[1]);\n\n              return [{\n                modeIndex,\n                masterGdtfChannel: masterChannel,\n                switchingChannelName: gdtfDmxChannel.$.Name,\n                followerGdtfChannel: gdtfDmxChannel,\n                followerChannelFunction: gdtfChannelFunction,\n                dmxFrom,\n                dmxTo,\n              }];\n            });\n          });\n        });\n      });\n    }\n\n    /**\n     * Parses <Relation Type=\"Mode\">'s relation data.\n     * This behavior is deprecated since GDTF v0.88, but still supported as a fallback.\n     * @returns {Relation[]} An array of relations, may be empty.\n     */\n    function getLegacyRelations() {\n      return gdtfFixture.DMXModes[0].DMXMode.flatMap((gdtfMode, modeIndex) => {\n        if (!('Relations' in gdtfMode) || typeof gdtfMode.Relations[0] !== 'object') {\n          return [];\n        }\n\n        return gdtfMode.Relations[0].Relation.flatMap((gdtfRelation) => {\n          if (gdtfRelation.$.Type !== 'Mode') {\n            return [];\n          }\n\n          const masterChannel = followXmlNodeReference(gdtfMode.DMXChannels[0], gdtfRelation.$.Master);\n\n          // Slave was renamed to Follower in GDTF v0.88\n          const followerChannelReference = gdtfRelation.$.Follower || gdtfRelation.$.Slave;\n          const followerChannel = followXmlNodeReference(gdtfMode.DMXChannels[0], followerChannelReference.split('.')[0]);\n          const followerChannelFunction = followXmlNodeReference(gdtfMode.DMXChannels[0], followerChannelReference);\n\n          const dmxFrom = getDmxValueWithResolutionFromGdtfDmxValue(gdtfRelation.$.DMXFrom, 0);\n          const maxDmxValue = Math.pow(256, dmxFrom[1]) - 1;\n          const dmxTo = getDmxValueWithResolutionFromGdtfDmxValue(gdtfRelation.$.DMXTo, maxDmxValue, dmxFrom[1]);\n\n          return [{\n            modeIndex,\n            masterGdtfChannel: masterChannel,\n            switchingChannelName: followerChannel.$.Name,\n            followerGdtfChannel: followerChannel,\n            followerChannelFunction,\n            dmxFrom,\n            dmxTo,\n          }];\n        });\n      });\n    }\n  }\n\n  /**\n   * @typedef {object} ChannelWrapper\n   * @property {string} key The channel key.\n   * @property {object} channel The OFL channel object.\n   * @property {number} maxResolution The highest used resolution of this channel.\n   * @property {number[]} modeIndices The indices of the modes that this channel is used in.\n   */\n\n  /**\n   * Add availableChannels and templateChannels to the fixture.\n   */\n  function addChannels() {\n    const availableChannels = [];\n    const templateChannels = [];\n\n    for (const gdtfMode of gdtfFixture.DMXModes[0].DMXMode) {\n      for (const gdtfChannel of gdtfMode.DMXChannels[0].DMXChannel) {\n        if (gdtfChannel.$.DMXBreak === 'Overwrite') {\n          addChannel(templateChannels, gdtfChannel);\n        }\n        else {\n          addChannel(availableChannels, gdtfChannel);\n        }\n      }\n    }\n\n    // append $pixelKey to templateChannels' keys and names\n    for (const channelWrapper of templateChannels) {\n      channelWrapper.key += ' $pixelKey';\n      channelWrapper.channel.name += ' $pixelKey';\n    }\n\n    cleanUpChannelWrappers([...availableChannels, ...templateChannels]);\n\n    // convert availableChannels array to object and add it to fixture\n    if (availableChannels.length > 0) {\n      fixture.availableChannels = Object.fromEntries(\n        availableChannels.map((channelWrapper) => [channelWrapper.key, channelWrapper.channel]),\n      );\n    }\n\n    // convert templateChannels array to object and add it to fixture\n    if (templateChannels.length > 0) {\n      fixture.templateChannels = Object.fromEntries(\n        templateChannels.map((channelWrapper) => [channelWrapper.key, channelWrapper.channel]),\n      );\n    }\n  }\n\n  /**\n   * @param {ChannelWrapper[]} channelWrappers The OFL availableChannels or templateChannels object.\n   * @param {object} gdtfChannel The GDTF <DMXChannel> XML object.\n   */\n  function addChannel(channelWrappers, gdtfChannel) {\n    const name = getChannelName();\n\n    if (gdtfChannel.LogicalChannel.length > 1) {\n      warnings.push(`DMXChannel '${name}' has more than one LogicalChannel. This is not supported yet and could lead to undesired results.`);\n    }\n\n    const modeIndex = gdtfFixture.DMXModes[0].DMXMode.findIndex(\n      (gdtfMode) => gdtfMode.DMXChannels[0].DMXChannel.includes(gdtfChannel),\n    );\n\n    const channel = {\n      name,\n      fineChannelAliases: [],\n      dmxValueResolution: '',\n      defaultValue: null,\n    };\n\n    if ('Default' in gdtfChannel.$) {\n      channel.defaultValue = getDmxValueWithResolutionFromGdtfDmxValue(gdtfChannel.$.Default);\n    }\n\n    if ('Highlight' in gdtfChannel.$ && gdtfChannel.$.Highlight !== 'None') {\n      channel.highlightValue = getDmxValueWithResolutionFromGdtfDmxValue(gdtfChannel.$.Highlight);\n    }\n\n    const capabilities = getCapabilities();\n\n    if (capabilities.length === 1) {\n      channel.capability = capabilities[0];\n      delete channel.capability.dmxRange;\n    }\n    else {\n      channel.capabilities = capabilities;\n    }\n\n    replaceGdtfDmxValuesWithNumbers();\n\n    // check if we already added the same channel in another mode\n    const sameChannel = channelWrappers.find(\n      (channelWrapper) => JSON.stringify(channelWrapper.channel) === JSON.stringify(channel) && !channelWrapper.modeIndices.includes(modeIndex),\n    );\n    if (sameChannel) {\n      gdtfChannel._oflChannelKey = sameChannel.key;\n\n      sameChannel.maxResolution = Math.max(sameChannel.maxResolution, getChannelResolution());\n      sameChannel.modeIndices.push(modeIndex);\n      return;\n    }\n\n    const channelKey = getChannelKey();\n\n    gdtfChannel._oflChannelKey = channelKey;\n    channelWrappers.push({\n      key: channelKey,\n      channel,\n      maxResolution: getChannelResolution(),\n      modeIndices: [modeIndex],\n    });\n\n    /**\n     * @returns {string} The channel name.\n     */\n    function getChannelName() {\n      const channelAttribute = gdtfChannel.LogicalChannel[0].$.Attribute;\n\n      try {\n        return gdtfFixture.AttributeDefinitions[0].Attributes[0].Attribute.find(\n          (attribute) => attribute.$.Name === channelAttribute,\n        ).$.Pretty || channelAttribute;\n      }\n      catch {\n        return channelAttribute;\n      }\n    }\n\n    /**\n     * @returns {object[]} Array of OFL capability objects (but with GDTF DMX values).\n     */\n    function getCapabilities() {\n      let minPhysicalValue = Number.POSITIVE_INFINITY;\n      let maxPhysicalValue = Number.NEGATIVE_INFINITY;\n\n      // save all <ChannelSet> XML nodes in a flat list\n      const gdtfCapabilities = gdtfChannel.LogicalChannel.flatMap((gdtfLogicalChannel) => {\n        if (!gdtfLogicalChannel.ChannelFunction) {\n          throw new Error(`LogicalChannel does not contain any ChannelFunction children in DMXChannel ${JSON.stringify(gdtfChannel, null, 2)}`);\n        }\n\n        return gdtfLogicalChannel.ChannelFunction.flatMap((gdtfChannelFunction) => {\n          if (!gdtfChannelFunction.ChannelSet) {\n            // add an empty <ChannelSet />\n            gdtfChannelFunction.ChannelSet = [{ $: {} }];\n          }\n\n          // save GDTF attribute for later\n          gdtfChannelFunction._attribute = followXmlNodeReference(\n            gdtfFixture.AttributeDefinitions[0].Attributes[0],\n            gdtfChannelFunction.$.Attribute,\n          ) || { $: { Name: 'NoFeature' } };\n\n          return gdtfChannelFunction.ChannelSet.map((gdtfChannelSet) => {\n            // save parent nodes for future use\n            gdtfChannelSet._logicalChannel = gdtfLogicalChannel;\n            gdtfChannelSet._channelFunction = gdtfChannelFunction;\n            gdtfChannelSet._fixture = gdtfFixture;\n\n            // do some preprocessing\n\n            if (!('$' in gdtfChannelSet)) {\n              gdtfChannelSet.$ = {};\n            }\n\n            if (!('Name' in gdtfChannelSet.$)) {\n              gdtfChannelSet.$.Name = '';\n            }\n\n            gdtfChannelSet._dmxFrom = getDmxValueWithResolutionFromGdtfDmxValue(gdtfChannelSet.$.DMXFrom, 0);\n\n            const physicalFrom = parseFloatWithFallback(gdtfChannelSet.$.PhysicalFrom, 0);\n            const physicalTo = parseFloatWithFallback(gdtfChannelSet.$.PhysicalTo, 1);\n\n            gdtfChannelSet._physicalFrom = physicalFrom;\n            gdtfChannelSet._physicalTo = physicalTo;\n\n            minPhysicalValue = Math.min(minPhysicalValue, physicalFrom, physicalTo);\n            maxPhysicalValue = Math.max(maxPhysicalValue, physicalFrom, physicalTo);\n\n            return gdtfChannelSet;\n          });\n        });\n      });\n\n      // Collapse a channel whose ChannelSets are a fully-redundant\n      // (Closed, …, Open) / (Open, …, Closed) wrapping of a single full-range\n      // Intensity / ColorIntensity capability into one synthesized ChannelSet.\n      const collapseTarget = getCollapseTarget();\n      const collapsedGdtfCapabilities = collapseTarget !== null && allChannelSetsMatchCollapseTarget(collapseTarget)\n        ? [createCollapsedChannelSet()]\n        : gdtfCapabilities;\n\n      return collapsedGdtfCapabilities.map((gdtfCapability, index) => {\n        const capability = {\n          dmxRange: [gdtfCapability._dmxFrom, getDmxRangeEnd(index)],\n        };\n\n        const gdtfAttribute = gdtfCapability._channelFunction._attribute;\n        const attributeName = gdtfAttribute.$.Name;\n        const capabilityTypeData = getCapabilityTypeData(attributeName);\n\n        capability.type = capabilityTypeData.oflType;\n\n        callHook(capabilityTypeData.beforePhysicalPropertyHook, capability, gdtfCapability, attributeName);\n\n        const oflProperty = getOflProperty(capabilityTypeData, gdtfCapability);\n\n        if (oflProperty !== null) {\n          const physicalUnit = getPhysicalUnit(gdtfCapability);\n\n          const physicalFrom = gdtfCapability._physicalFrom;\n          const physicalTo = gdtfCapability._physicalTo;\n\n          if (physicalFrom === physicalTo) {\n            capability[oflProperty] = physicalUnit(physicalFrom, null);\n          }\n          else {\n            capability[`${oflProperty}Start`] = physicalUnit(physicalFrom, physicalTo);\n            capability[`${oflProperty}End`] = physicalUnit(physicalTo, physicalFrom);\n\n            if (capability.brightnessStart === '0%' && capability.brightnessEnd === '100%') {\n              delete capability.brightnessStart;\n              delete capability.brightnessEnd;\n            }\n          }\n        }\n\n        callHook(capabilityTypeData.afterPhysicalPropertyHook, capability, gdtfCapability, attributeName);\n\n        if (gdtfCapability.$.Name) {\n          capability.comment = gdtfCapability.$.Name;\n        }\n\n        return capability;\n      });\n\n      /**\n       * @returns {object | null} The shared properties that every ChannelSet of\n       * this channel must match for the channel to collapse into a single\n       * full-range Intensity / ColorIntensity capability, or null if collapse\n       * is not applicable.\n       */\n      function getCollapseTarget() {\n        if (gdtfCapabilities.length < 2) {\n          return null;\n        }\n\n        const channelFunction = gdtfCapabilities[0]._channelFunction;\n        const oflType = getCapabilityTypeData(channelFunction._attribute.$.Name).oflType;\n        if (oflType !== 'Intensity' && oflType !== 'ColorIntensity') {\n          return null;\n        }\n\n        const closedNames = new Set(['Closed', 'closed', 'Min', 'min']);\n        const openNames = new Set(['Open', 'open', 'Max', 'max']);\n\n        const { _physicalFrom: physicalFrom, _physicalTo: physicalTo } = gdtfCapabilities[0];\n        if (physicalFrom === 0 && physicalTo === 1) {\n          return { channelFunction, physicalFrom, physicalTo, lowEndNames: closedNames, highEndNames: openNames };\n        }\n        if (physicalFrom === 1 && physicalTo === 0) {\n          return { channelFunction, physicalFrom, physicalTo, lowEndNames: openNames, highEndNames: closedNames };\n        }\n        return null;\n      }\n\n      /**\n       * @param {object} target The shared properties returned by `getCollapseTarget`.\n       * @returns {boolean} Whether every ChannelSet matches the target's shared\n       * properties and has a Name consistent with its position in the channel.\n       */\n      function allChannelSetsMatchCollapseTarget(target) {\n        const firstName = gdtfCapabilities[0].$.Name;\n        const lastName = gdtfCapabilities.at(-1).$.Name;\n        const middleHasName = gdtfCapabilities.slice(1, -1).some((capability) => capability.$.Name !== '');\n\n        if (\n          (firstName !== '' && !target.lowEndNames.has(firstName))\n          || (lastName !== '' && !target.highEndNames.has(lastName))\n          || middleHasName\n        ) {\n          return false;\n        }\n\n        return gdtfCapabilities.every((capability) =>\n          capability._channelFunction === target.channelFunction\n          && capability._physicalFrom === target.physicalFrom\n          && capability._physicalTo === target.physicalTo,\n        );\n      }\n\n      /**\n       * @returns {object} A synthesized ChannelSet that replaces all of\n       * `gdtfCapabilities` after a successful collapse check, copying the\n       * first ChannelSet's parent references and physical values but with an\n       * empty Name. The downstream `.map(...)` then turns this into a single\n       * OFL capability covering the channel's full DMX range.\n       */\n      function createCollapsedChannelSet() {\n        const firstCapability = gdtfCapabilities[0];\n        return {\n          $: { Name: '' },\n          _logicalChannel: firstCapability._logicalChannel,\n          _channelFunction: firstCapability._channelFunction,\n          _fixture: firstCapability._fixture,\n          _dmxFrom: firstCapability._dmxFrom,\n          _physicalFrom: firstCapability._physicalFrom,\n          _physicalTo: firstCapability._physicalTo,\n        };\n      }\n\n      /**\n       * @param {number} index The index of the capability.\n       * @returns {[number, Resolution]} The GDTF DMX value for this capability's range end.\n       */\n      function getDmxRangeEnd(index) {\n        const dmxFrom = collapsedGdtfCapabilities[index]._dmxFrom;\n\n        if (index === collapsedGdtfCapabilities.length - 1) {\n          // last capability\n          const resolution = dmxFrom[1];\n          return [Math.pow(256, resolution) - 1, resolution];\n        }\n\n        const [nextDmxFromValue, resolution] = collapsedGdtfCapabilities[index + 1]._dmxFrom;\n        return [nextDmxFromValue - 1, resolution];\n      }\n\n      /**\n       * @param {string} attributeName The GDTF attribute name.\n       * @returns {object} The capability type data from `gdtf-attributes.js`\n       */\n      function getCapabilityTypeData(attributeName) {\n        let capabilityTypeData = gdtfAttributes[attributeName];\n\n        if (!capabilityTypeData) {\n          const enumeratedAttributeName = attributeName.replace(/\\d+/, '(n)').replace(/\\d+/, '(m)');\n          capabilityTypeData = gdtfAttributes[enumeratedAttributeName];\n        }\n\n        if (!capabilityTypeData) {\n          return {\n            oflType: `Unknown (${attributeName})`, // will trigger an error in the validation\n            oflProperty: 'physical', // will also trigger an error, but the information could be useful\n          };\n        }\n\n        if (!capabilityTypeData.inheritFrom) {\n          return capabilityTypeData;\n        }\n\n        // save the inherited result for later access\n        gdtfAttributes[attributeName] = {\n\n          ...getCapabilityTypeData(capabilityTypeData.inheritFrom),\n          ...capabilityTypeData,\n        };\n        delete gdtfAttributes[attributeName].inheritFrom;\n\n        return gdtfAttributes[attributeName];\n      }\n\n      /**\n       * @param {((...args: unknown[]) => unknown) | null} hook The hook function, or a falsy value.\n       * @param {unknown[]} parameters The arguments to pass to the hook.\n       * @returns {unknown} The return value of the hook, or null if no hook was called.\n       */\n      function callHook(hook, ...parameters) {\n        if (hook) {\n          return hook(...parameters);\n        }\n\n        return null;\n      }\n\n      /**\n       * @param {object} capabilityTypeData The capability type data from `gdtf-attributes.js`\n       * @param {object} gdtfCapability The enhanced <ChannelSet> XML object.\n       * @returns {string | null} The OFL property name, or null.\n       */\n      function getOflProperty(capabilityTypeData, gdtfCapability) {\n        if (!('oflProperty' in capabilityTypeData)) {\n          return null;\n        }\n\n        if (typeof capabilityTypeData.oflProperty === 'function') {\n          return capabilityTypeData.oflProperty(gdtfCapability);\n        }\n\n        return capabilityTypeData.oflProperty;\n      }\n\n      /**\n       * @param {object} gdtfCapability The enhanced <ChannelSet> XML object.\n       * @returns {(value: number, otherValue?: number) => string} The function to turn a physical value into an entity string with the correct unit.\n       */\n      function getPhysicalUnit(gdtfCapability) {\n        const gdtfAttribute = gdtfCapability._channelFunction._attribute;\n        const capabilityTypeData = getCapabilityTypeData(gdtfAttribute.$.Name);\n\n        if (capabilityTypeData.oflProperty === 'index') {\n          return gdtfUnits.None;\n        }\n\n        let physicalEntity = gdtfAttribute.$.PhysicalUnit;\n\n        if (!physicalEntity) {\n          physicalEntity = 'None';\n\n          if (minPhysicalValue === 0 && maxPhysicalValue === 1) {\n            physicalEntity = 'Percent';\n          }\n          else if (capabilityTypeData.defaultPhysicalEntity) {\n            physicalEntity = capabilityTypeData.defaultPhysicalEntity;\n          }\n        }\n        else if (!(physicalEntity in gdtfUnits)) {\n          // ignore case of PhysicalUnit attribute\n          physicalEntity = Object.keys(gdtfUnits).find(\n            (entity) => entity.toLowerCase() === physicalEntity.toLowerCase(),\n          );\n        }\n\n        return gdtfUnits[physicalEntity];\n      }\n    }\n\n    /**\n     * @returns {number} The resolution of this channel.\n     */\n    function getChannelResolution() {\n      // The Offset attribute replaced the Coarse/Fine/Ultra/Uber attributes in GDTF v1.0\n      if ('Offset' in gdtfChannel.$) {\n        return gdtfChannel.$.Offset.split(',').length;\n      }\n\n      if (xmlNodeHasNotNoneAttribute(gdtfChannel, 'Uber')) {\n        return 4;\n      }\n\n      if (xmlNodeHasNotNoneAttribute(gdtfChannel, 'Ultra')) {\n        return 3;\n      }\n\n      if (xmlNodeHasNotNoneAttribute(gdtfChannel, 'Fine')) {\n        return 2;\n      }\n\n      return 1;\n    }\n\n    /**\n     * @returns {string} The channel key, derived from the name and made unique.\n     */\n    function getChannelKey() {\n      let key = name;\n\n      // make unique by appending ' 2', ' 3', ... if necessary\n      let duplicates = 1;\n      const keyExists = () => channelWrappers.some((channelWrapper) => channelWrapper.key === key);\n      while (keyExists()) {\n        duplicates++;\n        key = `${name} ${duplicates}`;\n      }\n\n      return key;\n    }\n\n    /**\n     * Look through all GDTF DMX values in this channel (consisting of DMX value\n     * and the resolution in which it is specified), make their resolution equal and\n     * replace them with a number. Then set the channel's dmxValueResolution to\n     * this resolution.\n     */\n    function replaceGdtfDmxValuesWithNumbers() {\n      const maxDmxValueResolution = getMaxDmxValueResolution();\n      const scaleToResolution = Math.max(CoarseChannel.RESOLUTION_8BIT, maxDmxValueResolution);\n\n      if (channel.defaultValue) {\n        channel.defaultValue = scaleDmxValue(...channel.defaultValue, scaleToResolution);\n      }\n\n      if (channel.highlightValue) {\n        channel.highlightValue = scaleDmxValue(...channel.highlightValue, scaleToResolution);\n      }\n\n      if (channel.capabilities) {\n        for (const capability of channel.capabilities) {\n          const startValue = capability.dmxRange[0][0];\n          const startResolution = capability.dmxRange[0][1];\n          const endValue = capability.dmxRange[1][0];\n          const endResolution = capability.dmxRange[1][1];\n\n          try {\n            capability.dmxRange = scaleDmxRangeIndividually(startValue, startResolution, endValue, endResolution, scaleToResolution);\n          }\n          catch {\n            // will be caught by validation\n            capability.dmxRange = [startValue, endValue];\n          }\n        }\n      }\n\n      if (maxDmxValueResolution !== 0) {\n        channel.dmxValueResolution = `${maxDmxValueResolution * 8}bit`;\n      }\n\n      /**\n       * @returns {number} The highest DMX value resolution used in this channel, or 0 if no DMX value is used at all.\n       */\n      function getMaxDmxValueResolution() {\n        const dmxValues = [];\n\n        if (channel.defaultValue && channel.defaultValue[0] !== 0) {\n          dmxValues.push(channel.defaultValue);\n        }\n\n        if (channel.highlightValue && channel.highlightValue[0] !== 0) {\n          dmxValues.push(channel.highlightValue);\n        }\n\n        if (channel.capabilities) {\n          for (const capability of channel.capabilities) {\n            dmxValues.push(capability.dmxRange[0], capability.dmxRange[1]);\n          }\n        }\n\n        return Math.max(0, ...dmxValues.map(\n          ([value, resolution]) => resolution,\n        ));\n      }\n    }\n  }\n\n  /**\n   * @typedef {object} DmxBreakWrapper Holds a list of OFL channel keys belonging to consecutive GDTF channels with the same DMXBreak attribute.\n   * @property {string | undefined} dmxBreak The DMXBreak attribute of consecutive DMXChannel nodes.\n   * @property {string} geometry The Geometry attribute of consecutive DMXChannel nodes.\n   * @property {string[]} channels The OFL channel keys in this DMX break.\n   */\n\n  /**\n   * Add modes and matrix pixel keys (if needed) to the fixture.\n   */\n  function addModes() {\n    // save all matrix pixels that are used in some mode\n    const matrixPixels = new Set();\n\n    fixture.modes = gdtfFixture.DMXModes[0].DMXMode.map((gdtfMode) => {\n      /** @type {DmxBreakWrapper[]} */\n      const dmxBreakWrappers = [];\n\n      for (const gdtfChannel of gdtfMode.DMXChannels[0].DMXChannel) {\n        if (dmxBreakWrappers.length === 0 || dmxBreakWrappers.at(-1).dmxBreak !== gdtfChannel.$.DMXBreak) {\n          dmxBreakWrappers.push({\n            dmxBreak: gdtfChannel.$.DMXBreak,\n            geometry: gdtfChannel.$.Geometry,\n            channels: [],\n          });\n        }\n\n        addChannelKeyToDmxBreakWrapper(gdtfChannel, dmxBreakWrappers);\n      }\n\n      const channels = [];\n\n      for (const channelWrapper of dmxBreakWrappers) {\n        if (channelWrapper.dmxBreak !== 'Overwrite') {\n          // just append the channels\n          channels.push(...channelWrapper.channels);\n          continue;\n        }\n\n        // append a matrix channel insert block\n\n        const geometryReferences = findGeometryReferences(channelWrapper.geometry);\n        const usedMatrixPixels = geometryReferences.map(\n          (gdtfGeoRef, index) => gdtfGeoRef.$.Name || `${channelWrapper.geometry} ${index + 1}`,\n        );\n\n        for (const pixelKey of usedMatrixPixels) {\n          matrixPixels.add(pixelKey);\n        }\n\n        channels.push({\n          insert: 'matrixChannels',\n          repeatFor: usedMatrixPixels,\n          channelOrder: 'perPixel',\n          templateChannels: channelWrapper.channels.map(\n            (channelKey) => `${channelKey} $pixelKey`,\n          ),\n        });\n      }\n\n      return {\n        name: gdtfMode.$.Name,\n        rdmPersonalityIndex: gdtfMode._oflRdmPersonalityIndex,\n        channels,\n      };\n    });\n\n    const matrixPixelList = [...matrixPixels];\n\n    fixture.matrix = {\n      pixelKeys: [\n        [\n          matrixPixelList,\n        ],\n      ],\n    };\n\n    // try to simplify matrix channel insert blocks\n    for (const mode of fixture.modes) {\n      for (const channel of mode.channels) {\n        if (typeof channel === 'object' && channel.insert === 'matrixChannels'\n          && JSON.stringify(matrixPixelList) === JSON.stringify(channel.repeatFor)) {\n          channel.repeatFor = 'eachPixelXYZ';\n        }\n      }\n    }\n\n    /**\n     * Adds the OFL channel key (and fine channel keys) to dmxBreakWrappers'\n     * last entry's channels array.\n     * @param {object} gdtfChannel The GDTF channel object.\n     * @param {DmxBreakWrapper[]} dmxBreakWrappers The DMXBreak wrapper array.\n     */\n    function addChannelKeyToDmxBreakWrapper(gdtfChannel, dmxBreakWrappers) {\n      const channelKey = gdtfChannel._oflChannelKey;\n      const oflChannel = fixture.availableChannels[channelKey];\n\n      const channels = dmxBreakWrappers.at(-1).channels;\n\n      const channelKeys = [channelKey, ...(oflChannel.fineChannelAliases ?? [])];\n\n      // The Offset attribute replaced the Coarse/Fine/Ultra/Uber attributes in GDTF v1.0\n      const channelOffsets = xmlNodeHasNotNoneAttribute(gdtfChannel, 'Offset')\n        ? gdtfChannel.$.Offset.split(',')\n        : [\n            gdtfChannel.$.Coarse,\n            gdtfChannel.$.Fine,\n            gdtfChannel.$.Ultra,\n            gdtfChannel.$.Uber,\n          ];\n\n      for (const [index, channelOffset] of channelOffsets.entries()) {\n        const dmxChannelNumber = Number.parseInt(channelOffset, 10);\n\n        if (!Number.isNaN(dmxChannelNumber)) {\n          channels[dmxChannelNumber - 1] = channelKeys[index];\n        }\n      }\n    }\n\n    /**\n     * Find all <GeometryReference> XML nodes with a given Geometry attribute.\n     * @param {string} geometryName The name of the geometry reference.\n     * @returns {object[]} An array of all geometry reference XML objects.\n     */\n    function findGeometryReferences(geometryName) {\n      const geometryReferences = [];\n\n      traverseGeometries(gdtfFixture.Geometries[0]);\n\n      return geometryReferences;\n\n      /**\n       * Recursively go through the child nodes of a given XML node and add\n       * <GeometryReference> nodes with the correct Geometry attribute to the\n       * geometryReferences array.\n       * @param {object} xmlNode The XML node object to start traversing at.\n       */\n      function traverseGeometries(xmlNode) {\n        // add all suitable GeometryReference child nodes\n        geometryReferences.push(\n          ...(xmlNode.GeometryReference || []).filter((gdtfGeoRef) => gdtfGeoRef.$.Geometry === geometryName),\n        );\n\n        // traverse all other child nodes\n        for (const [tagName, childNodes] of Object.entries(xmlNode)) {\n          if (tagName !== '$' && tagName !== 'GeometryReference') {\n            for (const childNode of childNodes) {\n              traverseGeometries(childNode);\n            }\n          }\n        }\n      }\n    }\n  }\n\n  /**\n   * Adds switchChannels property to all master channels' capabilities and use\n   * the switching channel key in modes' channel lists.\n   */\n  function linkSwitchingChannels() {\n    const { relationsPerMaster, modeChannelReplacements } = transformRelations(fixture, switchingChannelRelations);\n\n    // switch channels in trigger channels' capabilities\n    for (const triggerChannelKey of Object.keys(relationsPerMaster)) {\n      const triggerChannelRelations = simplifySwitchingChannelRelations(triggerChannelKey);\n\n      const triggerChannel = fixture.availableChannels?.[triggerChannelKey] ?? fixture.templateChannels[`${triggerChannelKey} $pixelKey`];\n\n      if (triggerChannel.defaultValue === null) {\n        triggerChannel.defaultValue = 0;\n      }\n\n      const channelResolution = getChannelResolution(triggerChannel);\n\n      for (const capability of triggerChannel.capabilities) {\n        capability.switchChannels = Object.fromEntries(Object.entries(triggerChannelRelations).flatMap(\n          ([switchingChannelKey, relations]) => relations\n            .filter((relation) => {\n              const [dmxFrom, dmxTo] = scaleDmxRangeIndividually(...relation.dmxFrom, ...relation.dmxTo, channelResolution);\n              return capability.dmxRange[0] >= dmxFrom && capability.dmxRange[1] <= dmxTo;\n            })\n            .map((relation) => [switchingChannelKey, relation.switchToChannelKey]),\n        ));\n      }\n    }\n\n    replaceSwitchingChannelsInModes(fixture, modeChannelReplacements);\n\n    /**\n     * @param {string} triggerChannelKey Key of the trigger channel, whose relations should be simplified.\n     * @returns {object} Simplified switching channel's relations.\n     */\n    function simplifySwitchingChannelRelations(triggerChannelKey) {\n      const simplifiedRelations = {};\n\n      for (const [switchingChannelKey, relations] of Object.entries(relationsPerMaster[triggerChannelKey])) {\n        // were this switching channel's relations already added?\n        const addedSwitchingChannelKey = Object.keys(simplifiedRelations).find(\n          (otherKey) => JSON.stringify(relationsPerMaster[triggerChannelKey][otherKey]) === JSON.stringify(relations),\n        );\n\n        if (addedSwitchingChannelKey) {\n          // already added switching channel has the same relations, so we don't need to add it\n          // but we need to update modeChannelReplacements\n          for (const mode of modeChannelReplacements) {\n            for (const channelKey of Object.keys(mode)) {\n              if (mode[channelKey] === switchingChannelKey) {\n                mode[channelKey] = addedSwitchingChannelKey;\n              }\n            }\n          }\n        }\n        else {\n          // add the new switching channel\n          simplifiedRelations[switchingChannelKey] = relations;\n        }\n      }\n\n      return simplifiedRelations;\n    }\n\n    /**\n     * @param {CoarseChannel} channel The OFL channel object.\n     * @returns {number} The fineness of the channel.\n     */\n    function getChannelResolution(channel) {\n      if ('dmxValueResolution' in channel) {\n        return Number.parseInt(channel.dmxValueResolution, 10) * 8;\n      }\n\n      if ('fineChannelAliases' in channel) {\n        return channel.fineChannelAliases.length + 1;\n      }\n\n      return CoarseChannel.RESOLUTION_8BIT;\n    }\n  }\n}\n\n/**\n * @param {Buffer} buffer The imported file.\n * @param {string} filename The imported file's name.\n * @returns {Promise<object>} A Promise that resolves to the parsed XML object.\n */\nasync function getGdtfXml(buffer, filename) {\n  let xmlString = buffer.toString();\n\n  if (filename.endsWith('.gdtf')) {\n    // unzip the .gdtf (zip) file and check its description.xml file\n    const zip = await JSZip.loadAsync(buffer);\n\n    const descriptionFile = zip.file('description.xml');\n    if (descriptionFile === null) {\n      throw new Error('The provided .gdtf (zip) file does not contain a \\'description.xml\\' file in the root directory.');\n    }\n\n    xmlString = await descriptionFile.async('string');\n  }\n\n  return xml2js.parseStringPromise(xmlString);\n}\n\n/**\n * Remove unnecessary `name` and `dmxValueResolution` properties and fill/remove\n * `fineChannelAliases`.\n * @param {ChannelWrapper[]} channelWrappers The OFL availableChannels or templateChannels objects.\n */\nfunction cleanUpChannelWrappers(channelWrappers) {\n  for (const channelWrapper of channelWrappers) {\n    const { key: channelKey, channel, maxResolution } = channelWrapper;\n\n    if (channelKey === channel.name) {\n      delete channel.name;\n    }\n\n    if (maxResolution === CoarseChannel.RESOLUTION_8BIT) {\n      delete channel.fineChannelAliases;\n    }\n    else {\n      // CoarseChannel.RESOLUTION_16BIT\n      channel.fineChannelAliases.push(`${channelKey} fine`);\n\n      for (let index = CoarseChannel.RESOLUTION_24BIT; index <= maxResolution; index++) {\n        channel.fineChannelAliases.push(`${channelKey} fine^${index - 1}`);\n      }\n    }\n\n    if (channel.dmxValueResolution === `${maxResolution * 8}bit` || channel.dmxValueResolution === '') {\n      delete channel.dmxValueResolution;\n    }\n  }\n}\n\n/**\n * @typedef {object} SwitchToChannelInfo\n * @property {[number, Resolution]} dmxFrom The DMX value and DMX resolution of the start of the DMX range triggering this relation.\n * @property {[number, Resolution]} dmxTo The DMX value and DMX resolution of the end of the DMX range triggering this relation.\n * @property {string} switchToChannelKey The key of the channel to switch to.\n */\n\n/**\n * @typedef {object} TransformedRelations\n * @property {Record<string, Record<string, SwitchToChannelInfo>>} relationsPerMaster An object mapping a master channel key and a switching channel key to the switch to channel information.\n * @property {ModeChannelReplacements} modeChannelReplacements An object mapping a mode index and a switch to channel key to the switching channel key.\n */\n\n/**\n * @typedef {Record<number, Record<string, string>>} ModeChannelReplacements\n * An object mapping a mode index and a switch to channel key to the switching channel key.\n */\n\n/**\n * Bring relations into a structure we can work with.\n * @param {object} fixture The OFL fixture object.\n * @param {Relation[]} switchingChannelRelations An array of relations.\n * @returns {TransformedRelations} The transformed relations.\n */\nfunction transformRelations(fixture, switchingChannelRelations) {\n  const relationsPerMaster = {};\n  const modeChannelReplacements = {};\n\n  // bring relations into a structure we can work with\n  for (const relation of switchingChannelRelations) {\n    const masterKey = relation.masterGdtfChannel._oflChannelKey;\n\n    if (!(masterKey in relationsPerMaster)) {\n      relationsPerMaster[masterKey] = {};\n    }\n\n    const modeIndex = relation.modeIndex;\n    const switchingChannelKey = `${modeIndex}_${relation.switchingChannelName}`;\n    const switchToChannelKey = relation.followerGdtfChannel._oflChannelKey;\n\n    if (!(switchingChannelKey in relationsPerMaster[masterKey])) {\n      relationsPerMaster[masterKey][switchingChannelKey] = [];\n    }\n\n    relationsPerMaster[masterKey][switchingChannelKey].push({\n      dmxFrom: relation.dmxFrom,\n      dmxTo: relation.dmxTo,\n      switchToChannelKey,\n    });\n\n    if (!modeChannelReplacements[modeIndex]) {\n      modeChannelReplacements[modeIndex] = {};\n    }\n\n    modeChannelReplacements[modeIndex][switchToChannelKey] = switchingChannelKey;\n\n    transformRelationFineChannels(relation, switchingChannelKey, switchToChannelKey);\n  }\n\n  return { relationsPerMaster, modeChannelReplacements };\n\n  /**\n   * Adds all implicit fine channel relations for a given relation.\n   * @param {Relation} relation The relation for the coarse channel.\n   * @param {string} switchingChannelKey The switching channel key of the coarse channel.\n   * @param {string} switchToChannelKey The switch to channel key of the coarse channel.\n   */\n  function transformRelationFineChannels(relation, switchingChannelKey, switchToChannelKey) {\n    const masterKey = relation.masterGdtfChannel._oflChannelKey;\n    const modeIndex = relation.modeIndex;\n\n    const switchToChannel = fixture.availableChannels[switchToChannelKey];\n    if (switchToChannel && 'fineChannelAliases' in switchToChannel) {\n      for (const [fineness, fineChannelAlias] of switchToChannel.fineChannelAliases.entries()) {\n        let switchingFineChannelKey = `${switchingChannelKey} fine`;\n        if (fineness > 0) {\n          switchingFineChannelKey += `^${fineness + 1}`;\n        }\n\n        if (!(switchingFineChannelKey in relationsPerMaster[masterKey])) {\n          relationsPerMaster[masterKey][switchingFineChannelKey] = [];\n        }\n\n        relationsPerMaster[masterKey][switchingFineChannelKey].push({\n          dmxFrom: relation.dmxFrom,\n          dmxTo: relation.dmxTo,\n          switchToChannelKey: fineChannelAlias,\n        });\n        modeChannelReplacements[modeIndex][fineChannelAlias] = switchingFineChannelKey;\n      }\n    }\n  }\n}\n\n/**\n * Replaces normal channels with switching channels in fixture's modes.\n * @param {object} fixture The OFL fixture object.\n * @param {ModeChannelReplacements} modeChannelReplacements An object mapping a mode index and a switch to channel key to the switching channel key.\n */\nfunction replaceSwitchingChannelsInModes(fixture, modeChannelReplacements) {\n  for (const [modeIndex, mode] of fixture.modes.entries()) {\n    if (!(modeIndex in modeChannelReplacements)) {\n      continue;\n    }\n\n    for (const switchToChannelKey of Object.keys(modeChannelReplacements[modeIndex])) {\n      const channelIndex = mode.channels.indexOf(switchToChannelKey);\n\n      if (channelIndex !== -1) {\n        mode.channels[channelIndex] = modeChannelReplacements[modeIndex][switchToChannelKey];\n      }\n    }\n  }\n}\n\n/**\n * Removes `defaultValue`s and fixture matrix if they're unneeded.\n * @param {object} fixture The OFL fixture object.\n * @param {string[]} warnings An array to add warnings to.\n */\nfunction cleanUpFixture(fixture, warnings) {\n  if ('availableChannels' in fixture) {\n    for (const channelKey of Object.keys(fixture.availableChannels)) {\n      const channel = fixture.availableChannels[channelKey];\n      if (channel.defaultValue === null) {\n        delete channel.defaultValue;\n      }\n    }\n  }\n\n  if ('templateChannels' in fixture) {\n    warnings.push('Please fix the visual representation of the matrix.');\n\n    for (const channelKey of Object.keys(fixture.templateChannels)) {\n      const channel = fixture.templateChannels[channelKey];\n      if (channel.defaultValue === null) {\n        delete channel.defaultValue;\n      }\n    }\n  }\n  else {\n    delete fixture.matrix;\n  }\n}\n\n/**\n * @param {object} xmlNode An XML node object.\n * @param {string} attribute The attribute name to check.\n * @returns {boolean} True if the node has the attribute and its value is not \"None\", false otherwise.\n */\nfunction xmlNodeHasNotNoneAttribute(xmlNode, attribute) {\n  return attribute in xmlNode.$ && xmlNode.$[attribute] !== 'None';\n}\n\n/**\n * GDTF date strings are already in ISO format. Before GDTF v1.0, date strings had\n * the form \"dd.MM.yyyy HH:mm:ss\", so those have to be converted to the ISO format.\n *\n * @see https://gdtf-share.com/wiki/GDTF_File_Description#attrType-date\n * @param {string | undefined} dateString An ISO date string or a date in the form \"dd.MM.yyyy HH:mm:ss\"\n * @param {string} fallbackDateString A fallback date string to return if the parsed date is not valid.\n * @returns {string} A date string in the form \"YYYY-MM-DD\" (may be the provided fallback date string).\n */\nfunction getIsoDateFromGdtfDate(dateString, fallbackDateString) {\n  if (!dateString) {\n    return fallbackDateString;\n  }\n\n  const isoDateMatch = dateString.match(/^(\\d{4}-\\d{2}-\\d{2})T/);\n  if (isoDateMatch !== null) {\n    return isoDateMatch[1];\n  }\n\n  const germanDateTimeRegex = /^([0-3]?\\d)\\.([01]?\\d)\\.(\\d{4})\\s+\\d?\\d:\\d?\\d:\\d?\\d$/;\n  const match = dateString.match(germanDateTimeRegex);\n\n  try {\n    const [, day, month, year] = match;\n    const date = new Date(Date.UTC(Number.parseInt(year, 10), Number.parseInt(month, 10) - 1, day));\n\n    return date.toISOString().replace(/T.*/, '');\n  }\n  catch {\n    return fallbackDateString;\n  }\n}\n\n/**\n * @param {string | undefined} dmxValueString GDTF DMX value in the form \"128/2\", see https://gdtf-share.com/wiki/GDTF_File_Description#attrType-DMXValue\n * @param {number | undefined} fallbackValue DMX value that is used if `dmxValueString` is falsy.\n * @param {number} [fallbackResolution=1] DMX value resolution that is used if `dmxValueString` is falsy.\n * @returns {[number, Resolution]} Array containing DMX value and DMX resolution.\n */\nfunction getDmxValueWithResolutionFromGdtfDmxValue(dmxValueString, fallbackValue, fallbackResolution = 1) {\n  if (!dmxValueString && fallbackValue !== undefined) {\n    return [fallbackValue, fallbackResolution];\n  }\n\n  try {\n    const [, value, resolution] = dmxValueString.match(/^(\\d+)\\/(\\d)$/);\n    return [Number.parseInt(value, 10), Number.parseInt(resolution, 10)];\n  }\n  catch {\n    return [Number.parseInt(dmxValueString, 10) || 0, 1];\n  }\n}\n\n/**\n * @param {string} value The string to parse.\n * @param {number} fallback The number to use if the string can't be parsed.\n * @returns {number} The parsed number.\n */\nfunction parseFloatWithFallback(value, fallback) {\n  const number = Number.parseFloat(value);\n  return Number.isNaN(number) ? fallback : number;\n}\n\n/**\n * @param {string} string The string to slugify.\n * @returns {string} A slugified version of the string, i.e. only containing lowercase letters, numbers and dashes.\n */\nfunction slugify(string) {\n  return string.toLowerCase().replaceAll(/[^\\da-z-]+/g, ' ').trim().replaceAll(/\\s+/g, '-');\n}\n"
  },
  {
    "path": "plugins/gdtf/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"GDTF 1.0\",\n  \"description\": [\n    \"<p><em>GDTF</em> stands for <em>General Device Type Format</em>. The file\",\n    \"format was originally conceived and jointly developed by MA Lighting,\",\n    \"Robe and Vectorworks to be an open standards technology. Manufacturers\",\n    \"involved in the entertainment design, production, and performance\",\n    \"industry are welcomed to participate in supporting GDTF.</p>\",\n    \"\",\n    \"<p>Since many manufacturers won't ever provide their fixture definitions\",\n    \"in GDTF and many lighting programs (including legacy ones) won't ever\",\n    \"understand them, the Open Fixture Library with this plugin is still\",\n    \"needed ;)</p>\"\n  ],\n  \"links\": {\n    \"GDTF file description\": \"https://github.com/mvrdevelopment/spec/blob/main/gdtf-spec.md\",\n    \"GDTF Share\": \"https://gdtf-share.com/\"\n  }\n}\n"
  },
  {
    "path": "plugins/millumin/export.js",
    "content": "import fixtureJsonStringify from '../../lib/fixture-json-stringify.js';\nimport CoarseChannel from '../../lib/model/CoarseChannel.js';\n/** @import Fixture from '../../lib/model/Fixture.js' */\n\nexport const version = '0.4.0';\n\n// needed for export test\nexport const supportedOflVersion = '7.3.0';\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  // one JSON file for each fixture\n  return fixtures.map((fixture) => {\n    try {\n      return getFixtureFile(fixture);\n    }\n    catch (error) {\n      throw new Error(`Exporting fixture ${fixture.manufacturer.key}/${fixture.key} failed: ${error}`, {\n        cause: error,\n      });\n    }\n  });\n}\n\n/**\n * @param {Fixture} fixture The fixture to export.\n * @returns {object} The generated fixture JSON file.\n */\nfunction getFixtureFile(fixture) {\n  const oflJson = structuredClone(fixture.jsonObject);\n  const milluminJson = {\n    $schema: `https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/schema-${supportedOflVersion}/schemas/fixture.json`,\n    name: oflJson.name,\n  };\n\n  addIfValidData(milluminJson, 'shortName', oflJson.shortName);\n  milluminJson.categories = getDowngradedCategories(oflJson.categories);\n  milluminJson.meta = oflJson.meta;\n  addIfValidData(milluminJson, 'comment', oflJson.comment);\n\n  if (oflJson.links && oflJson.links.manual) {\n    milluminJson.manualURL = fixture.getLinksOfType('manual')[0];\n  }\n\n  addIfValidData(milluminJson, 'helpWanted', oflJson.helpWanted);\n  addIfValidData(milluminJson, 'rdm', oflJson.rdm);\n  addIfValidData(milluminJson, 'physical', getDowngradedFixturePhysical(oflJson.physical || {}, fixture));\n  addIfValidData(milluminJson, 'matrix', getDowngradedMatrix(oflJson.matrix, fixture));\n\n  if (oflJson.availableChannels) {\n    milluminJson.availableChannels = Object.fromEntries(Object.entries(oflJson.availableChannels).map(\n      ([channelKey, jsonChannel]) => [channelKey, getDowngradedChannel(channelKey, jsonChannel, fixture)],\n    ));\n  }\n\n  if (oflJson.templateChannels) {\n    milluminJson.templateChannels = Object.fromEntries(Object.entries(oflJson.templateChannels).map(\n      ([channelKey, jsonChannel]) => [channelKey, getDowngradedChannel(channelKey, jsonChannel, fixture)],\n    ));\n  }\n\n  milluminJson.modes = oflJson.modes;\n\n  milluminJson.fixtureKey = fixture.key;\n  milluminJson.manufacturerKey = fixture.manufacturer.key;\n  milluminJson.oflURL = fixture.url;\n\n  return {\n    name: `${fixture.manufacturer.key}/${fixture.key}.json`,\n    content: fixtureJsonStringify(milluminJson),\n    mimetype: 'application/ofl-fixture',\n    fixtures: [fixture],\n  };\n}\n\n/**\n * Replaces the fixture's categories array with one that only includes categories\n * from the supported OFL schema version.\n * @param {string[]} categories The fixture's categories array.\n * @returns {string[]} A filtered categories array.\n */\nfunction getDowngradedCategories(categories) {\n  const replaceCategories = {\n    'Barrel Scanner': 'Effect',\n  };\n  const ignoredCategories = new Set(['Pixel Bar', 'Stand']);\n\n  const downgradedCategories = categories.flatMap((category) => {\n    if (ignoredCategories.has(category)) {\n      return [];\n    }\n\n    if (category in replaceCategories) {\n      category = replaceCategories[category];\n\n      if (categories.includes(category)) {\n        // replaced category is already used\n        return [];\n      }\n    }\n\n    return category;\n  });\n\n  if (downgradedCategories.length === 0) {\n    downgradedCategories.push('Other');\n  }\n\n  return downgradedCategories;\n}\n\n/**\n * Replaces the fixture's physical JSON object with one that fits to the supported OFL schema version.\n * Specifically, the outdated focus property (with type, panMax and tiltMax) is generated and added if needed.\n * @param {object} jsonPhysical The physical JSON that should be downgraded. May be an empty object.\n * @param {Fixture} fixture The fixture whose physical data should be downgraded.\n * @returns {object} The downgraded physical JSON object.\n */\nfunction getDowngradedFixturePhysical(jsonPhysical, fixture) {\n  const focusTypesCategories = {\n    Head: 'Moving Head',\n    Mirror: 'Scanner',\n    Barrel: 'Barrel Scanner',\n    Fixed: null,\n  };\n  const type = Object.keys(focusTypesCategories).find(\n    (focusType) => fixture.categories.includes(focusTypesCategories[focusType]),\n  ) || null;\n\n  const [panMax, tiltMax] = ['Pan', 'Tilt'].map((panOrTilt) => {\n    const capabilities = fixture.coarseChannels.flatMap((channel) => channel.capabilities || []);\n\n    const hasContinuousCapability = capabilities.some((capability) => capability.type === `${panOrTilt}Continuous`);\n    if (hasContinuousCapability) {\n      return 'infinite';\n    }\n\n    const panTiltCapabilities = capabilities.filter((capability) => capability.type === panOrTilt && capability.angle[0].unit === 'deg');\n    const minAngle = Math.min(...panTiltCapabilities.map((capability) => Math.min(capability.angle[0].number, capability.angle[1].number)));\n    const maxAngle = Math.max(...panTiltCapabilities.map((capability) => Math.max(capability.angle[0].number, capability.angle[1].number)));\n    const panTiltMax = maxAngle - minAngle;\n\n    if (panTiltMax > Number.NEGATIVE_INFINITY) {\n      return panTiltMax;\n    }\n\n    return null;\n  });\n\n  const focus = {\n    type,\n    panMax,\n    tiltMax,\n  };\n\n  // remove null properties\n  for (const [key, value] of Object.entries(focus)) {\n    if (value === null) {\n      delete focus[key];\n    }\n  }\n\n  if (Object.keys(focus).length > 0) {\n    jsonPhysical.focus = focus;\n\n    if (jsonPhysical.matrixPixels) {\n      // remove matrixPixels and add them again after focus\n      const matrixPixels = jsonPhysical.matrixPixels;\n      delete jsonPhysical.matrixPixels;\n      jsonPhysical.matrixPixels = matrixPixels;\n    }\n  }\n\n  delete jsonPhysical.powerConnectors;\n\n  // don't return empty objects\n  if (Object.keys(jsonPhysical).length > 0) {\n    return jsonPhysical;\n  }\n  return null;\n}\n\n/**\n * @param {object | undefined} jsonMatrix The matrix JSON data (if present) that should be downgraded.\n * @param {Fixture} fixture The fixture the matrix belongs to.\n * @returns {object} A downgraded version of the specified matrix object.\n */\nfunction getDowngradedMatrix(jsonMatrix, fixture) {\n  if (jsonMatrix && jsonMatrix.pixelGroups) {\n    for (const groupKey of Object.keys(jsonMatrix.pixelGroups)) {\n      jsonMatrix.pixelGroups[groupKey] = fixture.matrix.pixelGroups[groupKey];\n    }\n  }\n\n  return jsonMatrix;\n}\n\n/**\n * @param {string} channelKey A key that exists in given channelObject and specifies the channel that should be downgraded.\n * @param {object} jsonChannel The channel JSON data that should be downgraded.\n * @param {Fixture} fixture The fixture the channel belongs to.\n * @returns {object} A downgraded version of the specified channel object.\n */\nfunction getDowngradedChannel(channelKey, jsonChannel, fixture) {\n  const channel = new CoarseChannel(channelKey, jsonChannel, fixture);\n\n  const downgradedChannel = {};\n\n  addIfValidData(downgradedChannel, 'name', jsonChannel.name);\n  downgradedChannel.type = channel.type === 'NoFunction' ? 'Nothing' : channel.type;\n  addIfValidData(downgradedChannel, 'color', channel.color);\n  addIfValidData(downgradedChannel, 'fineChannelAliases', jsonChannel.fineChannelAliases);\n  addIfValidData(downgradedChannel, 'defaultValue', channel.hasDefaultValue, channel.defaultValue);\n  addIfValidData(downgradedChannel, 'highlightValue', channel.hasHighlightValue, channel.highlightValue);\n  addIfValidData(downgradedChannel, 'invert', channel.isInverted);\n  addIfValidData(downgradedChannel, 'constant', channel.isConstant);\n  addIfValidData(downgradedChannel, 'crossfade', channel.canCrossfade);\n  addIfValidData(downgradedChannel, 'precedence', jsonChannel.precedence);\n\n  if (capabilitiesNeeded()) {\n    downgradedChannel.capabilities = [];\n\n    for (const capability of channel.capabilities) {\n      const downgradedCapability = {\n        range: [capability.rawDmxRange.start, capability.rawDmxRange.end],\n        name: capability.name,\n      };\n\n      addIfValidData(downgradedCapability, 'menuClick', capability.jsonObject.menuClick);\n      if (capability.colors && capability.colors.allColors.length <= 2) {\n        downgradedCapability.color = capability.colors.allColors[0];\n\n        if (capability.colors.allColors[1]) {\n          downgradedCapability.color2 = capability.colors.allColors[1];\n        }\n      }\n      addIfValidData(downgradedCapability, 'helpWanted', capability.jsonObject.helpWanted);\n      addIfValidData(downgradedCapability, 'switchChannels', capability.jsonObject.switchChannels);\n\n      downgradedChannel.capabilities.push(downgradedCapability);\n    }\n  }\n\n  return downgradedChannel;\n\n  /**\n   * @returns {boolean} Whether or not it is needed to include capabilities in a downgraded version of this channel\n   */\n  function capabilitiesNeeded() {\n    const trivialCapabilityTypes = ['Intensity', 'ColorIntensity', 'Pan', 'Tilt', 'NoFunction'];\n    return channel.capabilities.length !== 1 || !trivialCapabilityTypes.includes(channel.capabilities[0].type);\n  }\n}\n\n/**\n * Saves the given data (or value, if given) into obj[property] if data is valid,\n * i.e. it is neither undefined, nor null, nor false.\n * @param {object} object The object where the property should be created.\n * @param {string} property The name of the property added to obj.\n * @param {unknown} data If this is valid, the property is added to obj.\n * @param {unknown} value The property value, if data is valid. Defaults to `data`.\n */\nfunction addIfValidData(object, property, data, value) {\n  if (value === undefined) {\n    value = data;\n  }\n\n  if (data !== undefined && data !== null && data !== false) {\n    object[property] = value;\n  }\n}\n"
  },
  {
    "path": "plugins/millumin/exportTests/json-schema-conformity.js",
    "content": "import https from 'https';\nimport Ajv from 'ajv';\nimport addFormats from 'ajv-formats';\nimport getAjvErrorMessages from '../../../lib/get-ajv-error-messages.js';\nimport { supportedOflVersion as SUPPORTED_OFL_VERSION } from '../export.js';\n\nconst SCHEMA_BASE_URL = `https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/schema-${SUPPORTED_OFL_VERSION}/schemas/`;\nconst SCHEMA_FILES = ['capability.json', 'channel.json', 'definitions.json', 'fixture.json'];\n\nconst schemas = await getSchemas();\n\n/**\n * @typedef {object} ExportFile\n * @property {string} name File name, may include slashes to provide a folder structure.\n * @property {string} content File content.\n * @property {string} mimetype File mime type.\n * @property {Fixture[] | null} fixtures Fixture objects that are described in given file; may be omitted if the file doesn't belong to any fixture (e.g. manufacturer information).\n * @property {string | null} mode Mode's shortName if given file only describes a single mode.\n */\n\n/**\n * @param {ExportFile} exportFile The file returned by the plugins' export module.\n * @param {ExportFile[]} allExportFiles An array of all export files.\n * @returns {Promise<void, string[] | string>} Resolve when the test passes or reject with an array of errors or one error if the test fails.\n */\nexport default async function testSchemaConformity(exportFile, allExportFiles) {\n  const ajv = new Ajv({\n    schemas,\n    strict: false,\n    verbose: true,\n  });\n  addFormats(ajv);\n  ajv.addFormat('color-hex', true);\n\n  const schemaValidate = ajv.getSchema('https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json');\n\n  const schemaValid = schemaValidate(JSON.parse(exportFile.content));\n  if (!schemaValid) {\n    throw getAjvErrorMessages(schemaValidate.errors, 'fixture');\n  }\n}\n\n/**\n * @returns {Promise<object[]>} Asynchronously downloaded and JSON parsed schemas. Already tweaked to handle Millumin's deviations from the supported schema version.\n */\nasync function getSchemas() {\n  const schemasJson = await Promise.all(SCHEMA_FILES.map(\n    (filename) => downloadSchema(SCHEMA_BASE_URL + filename),\n  ));\n\n  const fixtureSchema = schemasJson[SCHEMA_FILES.indexOf('fixture.json')];\n  const channelSchema = schemasJson[SCHEMA_FILES.indexOf('channel.json')];\n\n  // allow automatically added properties (but don't validate them)\n  fixtureSchema.properties.fixtureKey = true;\n  fixtureSchema.properties.manufacturerKey = true;\n  fixtureSchema.properties.oflURL = true;\n\n  // allow changed schema property\n  fixtureSchema.properties.$schema = { const: `${SCHEMA_BASE_URL}fixture.json` };\n  fixtureSchema.patternProperties = undefined;\n\n  // allow new colors from schema version 11.1.0\n  // see https://github.com/OpenLightingProject/open-fixture-library/pull/763\n  channelSchema.properties.color.enum.push('Warm White', 'Cold White');\n\n  return schemasJson;\n}\n\n/**\n * @param {string} url The schema URL to fetch\n * @returns {Promise<object>} A promise resolving to the JSON Schema object.\n */\nfunction downloadSchema(url) {\n  return new Promise((resolve, reject) => {\n    const request = https.get(url, (response) => {\n      if (response.statusCode < 200 || response.statusCode > 299) {\n        reject(new Error(`Failed to load page, status code: ${response.statusCode}`));\n      }\n\n      let body = '';\n      response.on('data', (chunk) => {\n        body += chunk;\n      });\n      response.on('end', () => resolve(JSON.parse(body)));\n    });\n\n    request.on('error', (error) => reject(error));\n  });\n}\n"
  },
  {
    "path": "plugins/millumin/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"Millumin\",\n  \"description\": [\n    \"<p>The Mac OS software <em>Millumin</em> gained support for (advanced)\",\n    \"light fixtures in version 3. The fixture format is essentially\",\n    \"<a href=\\\"https://github.com/OpenLightingProject/open-fixture-library/blob/schema-7.3.0/docs/fixture-format.md\\\">\",\n    \"the OFL format at schema version 7.3.0</a>, with a few additions.</p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://www.millumin.com/v3/\",\n    \"Millumin Help: Create a Light Show\": \"https://help.millumin.com/?page=01_tutorials_basics/light_show\"\n  },\n  \"fixtureUsage\": [\n    \"<p>Copy the exported fixtures into the library folder and restart\",\n    \"Millumin. For more information, see the Millumin Help link.</p>\"\n  ],\n  \"fileLocations\": {\n    \"subDirectoriesAllowed\": true,\n    \"Mac OS\": {\n      \"user\": \"~/Library/Millumin/\"\n    }\n  },\n  \"additionalInfo\": [\n    \"<h3>Additions to the OFL format at schema version 7.3.0</h3>\",\n    \"<ul>\",\n    \"<li>New top level properties <code>fixtureKey</code>, <code>manufacturerKey</code> and <code>oflURL</code></li>\",\n    \"<li><code>Warm White</code> and <code>Cold White</code> colors (from <a href=\\\"https://github.com/OpenLightingProject/open-fixture-library/blob/schema-11.1.0/docs/fixture-format.md\\\">schema version 11.1.0</a>)</li>\",\n    \"<ul>\"\n  ]\n}\n"
  },
  {
    "path": "plugins/ofl/export.js",
    "content": "import { fixtureSchema } from '../../lib/esm-shim.cjs';\nimport fixtureJsonStringify from '../../lib/fixture-json-stringify.js';\nimport importJson from '../../lib/import-json.js';\n/** @import Fixture from '../../lib/model/Fixture.js' */\n\nexport const version = fixtureSchema.version;\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const displayedPluginVersion = options.displayedPluginVersion || version;\n\n  const usedManufacturers = new Set();\n\n  // one JSON file for each fixture\n  const files = fixtures.map((fixture) => {\n    usedManufacturers.add(fixture.manufacturer.key);\n\n    try {\n      return getFixtureFile(fixture, displayedPluginVersion);\n    }\n    catch (error) {\n      throw new Error(`Exporting fixture ${fixture.manufacturer.key}/${fixture.key} failed: ${error}`, {\n        cause: error,\n      });\n    }\n  });\n\n  const manufacturers = await importJson('../../fixtures/manufacturers.json', import.meta.url);\n\n  // manufacturers.json file\n  const usedManufacturerData = {\n    $schema: `https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/schema-${displayedPluginVersion}/schemas/manufacturers.json`,\n  };\n  for (const manufacturer of Object.keys(manufacturers).toSorted()) {\n    if (usedManufacturers.has(manufacturer)) {\n      usedManufacturerData[manufacturer] = manufacturers[manufacturer];\n    }\n  }\n  files.push({\n    name: 'manufacturers.json',\n    content: `${JSON.stringify(usedManufacturerData, null, 2)}\\n`,\n    mimetype: 'application/ofl-manufacturers',\n  });\n\n  return files;\n}\n\n/**\n * @param {Fixture} fixture The fixture to export.\n * @param {string} displayedPluginVersion The plugin version that should be displayed in the exported file.\n * @returns {object} The generated fixture JSON file.\n */\nfunction getFixtureFile(fixture, displayedPluginVersion) {\n  const jsonData = structuredClone(fixture.jsonObject);\n  jsonData.$schema = `https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/schema-${displayedPluginVersion}/schemas/fixture.json`;\n\n  jsonData.fixtureKey = fixture.key;\n  jsonData.manufacturerKey = fixture.manufacturer.key;\n  jsonData.oflURL = fixture.url;\n\n  return {\n    name: `${fixture.manufacturer.key}/${fixture.key}.json`,\n    content: fixtureJsonStringify(jsonData),\n    mimetype: 'application/ofl-fixture',\n    fixtures: [fixture],\n  };\n}\n"
  },
  {
    "path": "plugins/ofl/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"Open Fixture Library JSON\",\n  \"description\": [\n    \"<p>Outputs the fixture's JSON object (like stored in the repository, just\",\n    \"not as prettily printed) plus <code>fixtureKey</code>,\",\n    \"<code>manufacturerKey</code> and <code>oflURL</code> (a link to the\",\n    \"fixture page on <a href=\\\"https://open-fixture-library.org\\\">open-fixture-library.org</a>).\",\n    \"Additionally, the <code>$schema</code> property points to the JSON\",\n    \"Schema in the current schema version.</p>\",\n    \"\",\n    \"<p><em>In general, the OFL JSON format wasn't built for the use in\",\n    \"lighting software programs.</em> It is likely to break backwards\",\n    \"compatibility with future changes, so every developer who uses the OFL\",\n    \"format has to actively follow the development.</p>\"\n  ],\n  \"links\": {\n    \"Fixture format documentation\": \"https://github.com/OpenLightingProject/open-fixture-library/blob/master/docs/fixture-format.md\",\n    \"Schema versions\": \"https://github.com/OpenLightingProject/open-fixture-library/releases\"\n  }\n}\n"
  },
  {
    "path": "plugins/op-z/export.js",
    "content": "import CoarseChannel from '../../lib/model/CoarseChannel.js';\nimport FineChannel from '../../lib/model/FineChannel.js';\nimport NullChannel from '../../lib/model/NullChannel.js';\nimport SwitchingChannel from '../../lib/model/SwitchingChannel.js';\n/** @import AbstractChannel from '../../lib/model/AbstractChannel.js' */\n/** @import Fixture from '../../lib/model/Fixture.js' */\n\nexport const version = '0.1.0';\n\nconst MAX_KNOBS = 8;\nconst MAX_OPZ_FIXTURES = 16;\n\nlet usedKnobs = {};\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const exportJson = {\n    profiles: [],\n    config: [],\n  };\n\n  usedKnobs = {};\n\n  for (const fixture of fixtures) {\n    const fixtureKey = `${fixture.manufacturer.key}/${fixture.key}`;\n\n    for (const [modeIndex, mode] of fixture.modes.entries()) {\n      const modeName = `${fixtureKey}/${mode.shortName}`;\n\n      // add profile\n      exportJson.profiles.push({\n        name: modeName,\n        channels: mode.channels.map((channel) => getOpZChannelType(channel, fixtureKey)),\n      });\n\n      // add config\n      if (modeIndex === 0 && exportJson.config.length < MAX_OPZ_FIXTURES) {\n        exportJson.config.push({\n          fixture: exportJson.config.length + 1,\n          profile: modeName,\n        });\n      }\n    }\n  }\n\n  return [{\n    name: 'dmx.json',\n    content: JSON.stringify(exportJson, null, 2),\n    mimetype: 'application/json',\n    fixtures,\n  }];\n}\n\n/**\n * @param {AbstractChannel} channel The OFL channel object.\n * @param {string} fixtureKey The OFL fixture key.\n * @returns {string} The OP-Z channel type.\n */\nfunction getOpZChannelType(channel, fixtureKey) {\n  if (channel instanceof SwitchingChannel) {\n    channel = channel.defaultChannel;\n  }\n\n  if (channel instanceof NullChannel || channel instanceof FineChannel) {\n    return 'off';\n  }\n\n  const defaultValue = channel.getDefaultValueWithResolution(CoarseChannel.RESOLUTION_8BIT);\n\n  const opZChannelTypes = {\n    [`${defaultValue}`]: () => channel.isConstant || channel.type === 'Shutter',\n    red: () => channel.color === 'Red',\n    green: () => channel.color === 'Green',\n    blue: () => channel.color === 'Blue',\n    white: () => channel.color === 'White',\n    color: () => channel.type === 'Multi-Color',\n    intensity: () => channel.type === 'Intensity',\n    fog: () => channel.type === 'Fog',\n    // 'knob1': () => false,\n    // 'knob2': () => false,\n    // 'knob3': () => false,\n    // 'knob4': () => false,\n    // 'knob5': () => false,\n    // 'knob6': () => false,\n    // 'knob7': () => false,\n    // 'knob8': () => false,\n    // 'on': () => false,\n    off: () => channel.type === 'Maintenance',\n  };\n\n  const channelType = Object.keys(opZChannelTypes).find(\n    (type) => opZChannelTypes[type](),\n  );\n  if (channelType) {\n    return channelType;\n  }\n\n  return getKnobType(channel, fixtureKey) || `${defaultValue}`;\n}\n\n/**\n * Try to use a `knobX` OP-Z channel type for this channel. A channel used\n * across different modes will get the same knob again. null is returned\n * for all channels after all knobs are already assigned.\n * @param {AbstractChannel} channel The OFL channel object.\n * @param {string} fixtureKey The OFL fixture key.\n * @returns {string | null} The OP-Z channel type `knobX` if applicable, null otherwise.\n */\nfunction getKnobType(channel, fixtureKey) {\n  const channelKey = `${fixtureKey}/${channel.key}`;\n  if (channelKey in usedKnobs) {\n    return usedKnobs[channelKey];\n  }\n\n  const usedKnobCount = Object.keys(usedKnobs).length;\n  if (usedKnobCount < MAX_KNOBS) {\n    usedKnobs[channelKey] = `knob${usedKnobCount + 1}`;\n\n    return usedKnobs[channelKey];\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "plugins/op-z/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"OP-Z\",\n  \"description\": [\n    \"<p>Teenage Engineering's OP-Z synthesizer and sequencer has a separate\",\n    \"track for controlling light fixtures via DMX. The DMX configuration is\",\n    \"saved in a <code>dmx.json</code> file. This OFL plugin exports that file\",\n    \"for a given set of fixtures, however, it is likely that it needs manual\",\n    \"adjustments to fit the exact configuration and workflow of the user.</p>\",\n    \"\",\n    \"<p>The OP-Z only allows 16 fixtures to be used at the same time, so the\",\n    \"<code>config</code> section will only include the first mode of the first\",\n    \"16 fixtures; the <code>profiles</code> section will contain all.</p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://teenage.engineering/products/op-z\",\n    \"OP-Z online manual: Lights\": \"https://teenage.engineering/guides/op-z/lights\"\n  },\n  \"fileLocations\": {\n    \"OP-Z in content mode\": {\n      \"main\": \"/config/dmx.json\"\n    }\n  },\n  \"additionalInfo\": [\n    \"<h3>OP-Z channel types</h3>\",\n    \"\",\n    \"<p><em>This table is taken from the <code>how_to_dmx.txt</code> file in\",\n    \"OP-Z's content mode.</em></p>\",\n    \"\",\n    \"<p><strong>Note:</strong> The table in the OP-Z online manual is out of\",\n    \"date. <code>dial 1</code> there is now actually <code>knob1</code> (and\",\n    \"so on).</p>\",\n    \"\",\n    \"<table>\",\n    \"<tr>\",\n    \"  <th scope=\\\"col\\\">channel</th>\",\n    \"  <th scope=\\\"col\\\">range</th>\",\n    \"  <th scope=\\\"col\\\">description</th>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>red</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>red color</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>green</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>green color</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>blue</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>blue color</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>white</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>white color</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>color</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>color wheel</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>intensity</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>intensity / dimmer</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>fog</code></td>\",\n    \"  <td>0, 255</td>\",\n    \"  <td>triggered by animation 14</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>knob1</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>green knob (page 1)</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>knob2</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>blue knob (page 1)</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>knob3</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>yellow knob (page 1)</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>knob4</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>red knob (page 1)</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>knob5</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>green knob (page 2)</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>knob6</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>blue knob (page 2)</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>knob7</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>yellow knob (page 2)</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>knob8</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>red knob (page 2)</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>0 – 255</code></td>\",\n    \"  <td>0 – 255</td>\",\n    \"  <td>custom fixed value</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>on</code></td>\",\n    \"  <td>255</td>\",\n    \"  <td>always on</td>\",\n    \"</tr>\",\n    \"<tr>\",\n    \"  <td><code>off</code></td>\",\n    \"  <td>0</td>\",\n    \"  <td>always off</td>\",\n    \"</tr>\",\n    \"</table>\",\n    \"\",\n    \"<p><strong>Help wanted:</strong> One of the example fixtures in the OP-Z's\",\n    \"default <code>dmx.json</code> contains a <code>strobe</code> channel.\",\n    \"Is that channel type actually supported? Please help us support it,\",\n    \"should it be available.</p>\",\n    \"<p>The knobs are assigned to the first 8 DMX channels that are not\",\n    \"natively supported by the OP-Z (i.e. color channels, intensity and fog\",\n    \"channels). The same channel in different modes is assigned the same knob.\",\n    \"After all knobs are assigned, remaining channels are just represented by\",\n    \"their default DMX value. Fine channels and null channels are always\",\n    \"<code>off</code>.</p>\"\n  ],\n  \"helpWanted\": \"One of the example fixtures in the OP-Z's default <code>dmx.json</code> contains a <code>strobe</code> channel. Is that channel type actually supported?\"\n}\n"
  },
  {
    "path": "plugins/plugins.json",
    "content": "{\n  \"importPlugins\": [\n    \"ecue\",\n    \"gdtf\",\n    \"qlcplus_4.12.2\"\n  ],\n  \"exportPlugins\": [\n    \"aglight\",\n    \"color-chief\",\n    \"colorsource\",\n    \"d-light\",\n    \"dmxcontrol3\",\n    \"dragonframe\",\n    \"ecue\",\n    \"millumin\",\n    \"ofl\",\n    \"op-z\",\n    \"qlcplus_4.12.2\"\n  ],\n  \"data\": {\n    \"aglight\": {\n      \"name\": \"AGLight\",\n      \"exportPluginVersion\": \"1.0.0\",\n      \"exportTests\": []\n    },\n    \"color-chief\": {\n      \"name\": \"Eurolite Color Chief 2.0\",\n      \"exportPluginVersion\": \"1.0.0\",\n      \"exportTests\": []\n    },\n    \"colorsource\": {\n      \"name\": \"ColorSource\",\n      \"exportPluginVersion\": \"0.1.0\",\n      \"exportTests\": []\n    },\n    \"d-light\": {\n      \"name\": \"D::Light\",\n      \"exportPluginVersion\": \"0.2.0\",\n      \"exportTests\": [\n        \"attributes-correctness\"\n      ]\n    },\n    \"dmxcontrol3\": {\n      \"name\": \"DMXControl 3 (DDF3)\",\n      \"exportPluginVersion\": \"0.1.2\",\n      \"exportTests\": [\n        \"channel-numbers\"\n      ]\n    },\n    \"dragonframe\": {\n      \"name\": \"Dragonframe\",\n      \"exportPluginVersion\": \"1.0.0\",\n      \"exportTests\": [\n        \"json-schema-conformity\"\n      ]\n    },\n    \"ecue\": {\n      \"name\": \"e:cue\",\n      \"importPluginVersion\": \"0.3.1\",\n      \"exportPluginVersion\": \"0.3.0\",\n      \"exportTests\": []\n    },\n    \"gdtf\": {\n      \"name\": \"GDTF 1.0\",\n      \"importPluginVersion\": \"0.2.0\"\n    },\n    \"millumin\": {\n      \"name\": \"Millumin\",\n      \"exportPluginVersion\": \"0.4.0\",\n      \"exportTests\": [\n        \"json-schema-conformity\"\n      ]\n    },\n    \"ofl\": {\n      \"name\": \"Open Fixture Library JSON\",\n      \"exportPluginVersion\": \"12.5.0\",\n      \"exportTests\": []\n    },\n    \"op-z\": {\n      \"name\": \"OP-Z\",\n      \"exportPluginVersion\": \"0.1.0\",\n      \"exportTests\": []\n    },\n    \"qlcplus\": {\n      \"name\": \"QLC+\",\n      \"outdated\": true,\n      \"newPlugin\": \"qlcplus_4.12.2\"\n    },\n    \"qlcplus_4.11.2\": {\n      \"name\": \"QLC+ 4.11.2\",\n      \"outdated\": true,\n      \"newPlugin\": \"qlcplus_4.12.2\"\n    },\n    \"qlcplus_4.12.0\": {\n      \"name\": \"QLC+ 4.12.0\",\n      \"outdated\": true,\n      \"newPlugin\": \"qlcplus_4.12.2\"\n    },\n    \"qlcplus_4.12.1\": {\n      \"name\": \"QLC+ 4.12.1\",\n      \"outdated\": true,\n      \"newPlugin\": \"qlcplus_4.12.2\"\n    },\n    \"qlcplus_4.12.2\": {\n      \"name\": \"QLC+ 4.12.2\",\n      \"importPluginVersion\": \"1.1.2\",\n      \"exportPluginVersion\": \"1.3.2\",\n      \"exportTests\": [\n        \"fixture-tool-validation\",\n        \"xsd-schema-conformity\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/qlcplus_4.12.2/export.js",
    "content": "import sanitize from 'sanitize-filename';\nimport xmlbuilder from 'xmlbuilder';\nimport Capability from '../../lib/model/Capability.js';\nimport CoarseChannel from '../../lib/model/CoarseChannel.js';\nimport Physical from '../../lib/model/Physical.js';\nimport SwitchingChannel from '../../lib/model/SwitchingChannel.js';\nimport {\n  exportHelpers,\n  getCapabilityPreset,\n  getChannelPreset,\n  getFineChannelPreset,\n} from './presets.js';\n/** @import AbstractChannel from '../../lib/model/AbstractChannel.js' */\n/** @import FineChannel from '../../lib/model/FineChannel.js' */\n/** @import Fixture from '../../lib/model/Fixture.js' */\n/** @import Mode from '../../lib/model/Mode.js' */\n\nexport const version = '1.3.2';\n\n/**\n * @param {Fixture[]} fixtures An array of Fixture objects.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @returns {Promise<object[], Error>} The generated files.\n */\nexport async function exportFixtures(fixtures, options) {\n  const customGobos = {};\n\n  const outFiles = await Promise.all(fixtures.map(async (fixture) => {\n    try {\n      return await getFixtureFile(fixture, options, customGobos);\n    }\n    catch (error) {\n      throw new Error(`Exporting fixture ${fixture.manufacturer.key}/${fixture.key} failed: ${error}`, {\n        cause: error,\n      });\n    }\n  }));\n\n  // add gobo images not included in QLC+ to exported files\n  for (const [qlcplusResourceName, oflResource] of Object.entries(customGobos)) {\n    const fileContent = (oflResource.imageEncoding === 'base64')\n      ? Buffer.from(oflResource.imageData, 'base64')\n      : oflResource.imageData;\n\n    outFiles.push({\n      name: `gobos/${qlcplusResourceName}`,\n      content: fileContent,\n      mimeType: oflResource.imageMimeType,\n    });\n  }\n\n  return outFiles;\n}\n\n/**\n * @param {Fixture} fixture The fixture to export.\n * @param {object} options Global options, including:\n * @param {string} options.baseDirectory Absolute path to OFL's root directory.\n * @param {Date} options.date The current time.\n * @param {string | undefined} options.displayedPluginVersion Replacement for plugin version if the plugin version is used in export.\n * @param {object} customGobos An object where gobo resources not included in QLC+ can be added to.\n * @returns {Promise<object>} The generated fixture file.\n */\nasync function getFixtureFile(fixture, options, customGobos) {\n  const xml = xmlbuilder.begin()\n    .declaration('1.0', 'utf-8')\n    .element({\n      FixtureDefinition: {\n        // eslint-disable-next-line sonarjs/no-clear-text-protocols -- HTTP required by QLC+, this is an identifier rather than a real URL anyway\n        '@xmlns': 'http://www.qlcplus.org/FixtureDefinition',\n        'Creator': {\n          Name: `OFL – ${fixture.url}`,\n          Version: options.displayedPluginVersion || version,\n          Author: fixture.meta.authors.join(', '),\n        },\n        'Manufacturer': fixture.manufacturer.name,\n        'Model': fixture.name,\n        'Type': getFixtureType(fixture),\n      },\n    });\n\n  for (const channel of fixture.coarseChannels) {\n    await addChannel(xml, channel, customGobos);\n  }\n\n  const panMax = getPanTiltMax('Pan', fixture.coarseChannels);\n  const tiltMax = getPanTiltMax('Tilt', fixture.coarseChannels);\n  const useGlobalPhysical = fixture.modes.every((mode) => {\n    if (mode.physicalOverride !== null) {\n      return false;\n    }\n\n    const modePanMax = getPanTiltMax('Pan', mode.channels);\n    const modeTiltMax = getPanTiltMax('Tilt', mode.channels);\n    return (modePanMax === 0 || panMax === modePanMax) && (modeTiltMax === 0 || tiltMax === modeTiltMax);\n  });\n\n  for (const mode of fixture.modes) {\n    addMode(xml, mode, !useGlobalPhysical);\n  }\n\n  if (useGlobalPhysical) {\n    addPhysical(xml, fixture.physical || new Physical({}), fixture);\n  }\n\n  xml.dtd('');\n\n  const sanitizedFileName = sanitize(`${fixture.manufacturer.name}-${fixture.name}.qxf`).replaceAll(/\\s+/g, '-');\n\n  return {\n    name: `fixtures/${sanitizedFileName}`,\n    content: xml.end({\n      pretty: true,\n      indent: ' ',\n    }),\n    mimetype: 'application/x-qlc-fixture',\n  };\n}\n\n/**\n * @param {object} xml The xmlbuilder <FixtureDefinition> object.\n * @param {CoarseChannel} channel The OFL channel object.\n * @param {object} customGobos An object where gobo resources not included in QLC+ can be added to.\n */\nasync function addChannel(xml, channel, customGobos) {\n  const channelType = getChannelType(channel.type);\n\n  const xmlChannel = xml.element({\n    Channel: {\n      '@Name': channel.uniqueName,\n    },\n  });\n\n  if (channel.defaultValue !== 0) {\n    xmlChannel.attribute('Default', channel.getDefaultValueWithResolution(CoarseChannel.RESOLUTION_8BIT));\n  }\n\n  const channelPreset = getChannelPreset(channel);\n  if (channelPreset === null) {\n    xmlChannel.element({\n      Group: {\n        '@Byte': 0,\n        '#text': channelType,\n      },\n    });\n\n    if (channelType === 'Intensity') {\n      xmlChannel.element({\n        Colour: channel.color === null ? 'Generic' : channel.color.replace(/^(?:Warm|Cold) /, ''),\n      });\n    }\n\n    for (const capability of channel.capabilities) {\n      await addCapability(xmlChannel, capability, customGobos);\n    }\n  }\n  else {\n    xmlChannel.attribute('Preset', channelPreset);\n  }\n\n  for (const fineChannel of channel.fineChannels) {\n    await addFineChannel(xml, fineChannel, customGobos);\n  }\n}\n\n/**\n * @param {object} xml The xmlbuilder <FixtureDefinition> object.\n * @param {FineChannel} fineChannel The OFL fine channel object.\n * @param {object} customGobos An object where gobo resources not included in QLC+ can be added to.\n */\nasync function addFineChannel(xml, fineChannel, customGobos) {\n  if (!fineChannel.fixture.allChannels.includes(fineChannel)) {\n    return;\n  }\n\n  const xmlFineChannel = xml.element({\n    Channel: {\n      '@Name': fineChannel.uniqueName,\n    },\n  });\n\n  if (fineChannel.defaultValue !== 0) {\n    xmlFineChannel.attribute('Default', fineChannel.defaultValue);\n  }\n\n  if (fineChannel.resolution > CoarseChannel.RESOLUTION_16BIT) {\n    // QLC+ does not support 24+ bit channels, so let's fake one\n    xmlFineChannel.element({\n      Group: {\n        '@Byte': 0, // not a QLC+ fine channel\n        '#text': 'Maintenance',\n      },\n    });\n\n    await addCapability(xmlFineChannel, new Capability({\n      dmxRange: [0, 255],\n      type: 'Generic',\n      comment: `Fine^${fineChannel.resolution - 1} adjustment for ${fineChannel.coarseChannel.uniqueName}`,\n    }, CoarseChannel.RESOLUTION_8BIT, fineChannel.coarseChannel), customGobos);\n\n    return;\n  }\n\n  const fineChannelPreset = getFineChannelPreset(fineChannel);\n  if (fineChannelPreset !== null) {\n    xmlFineChannel.attribute('Preset', fineChannelPreset);\n\n    return;\n  }\n\n  const channelType = getChannelType(fineChannel.coarseChannel.type);\n\n  xmlFineChannel.element({\n    Group: {\n      '@Byte': 1,\n      '#text': channelType,\n    },\n  });\n\n  if (channelType === 'Intensity') {\n    xmlFineChannel.element({\n      Colour: fineChannel.coarseChannel.color === null ? 'Generic' : fineChannel.coarseChannel.color.replace(/^(?:Warm|Cold) /, ''),\n    });\n  }\n\n  await addCapability(xmlFineChannel, new Capability({\n    dmxRange: [0, 255],\n    type: 'Generic',\n    comment: `Fine adjustment for ${fineChannel.coarseChannel.uniqueName}`,\n  }, CoarseChannel.RESOLUTION_8BIT, fineChannel.coarseChannel));\n}\n\n/**\n * @param {object} xmlChannel The xmlbuilder <Channel> object.\n * @param {Capability} capability The OFL capability object.\n * @param {object} customGobos An object where gobo resources not included in QLC+ can be added to.\n */\nasync function addCapability(xmlChannel, capability, customGobos) {\n  const dmxRange = capability.getDmxRangeWithResolution(CoarseChannel.RESOLUTION_8BIT);\n\n  const xmlCapability = xmlChannel.element({\n    Capability: {\n      '@Min': dmxRange.start,\n      '@Max': dmxRange.end,\n      '#text': capability.name,\n    },\n  });\n\n  const preset = addCapabilityAliases(xmlCapability, capability)\n    ? {\n        presetName: 'Alias',\n        res1: null,\n        res2: null,\n      }\n    : await getCapabilityPreset(capability);\n\n  if (preset === null) {\n    await addCapabilityLegacyAttributes(xmlCapability, capability, customGobos);\n  }\n  else {\n    xmlCapability.attribute('Preset', preset.presetName);\n\n    if (preset.res1 !== null) {\n      xmlCapability.attribute('Res1', preset.res1);\n\n      if (`${preset.res1}`.startsWith('ofl/')) {\n        customGobos[preset.res1] = capability.wheelSlot[0].resource;\n      }\n    }\n\n    if (preset.res2 !== null) {\n      xmlCapability.attribute('Res2', preset.res2);\n    }\n  }\n}\n\n/**\n * @param {object} xmlCapability The xmlbuilder <Capability> object.\n * @param {Capability} capability The OFL capability object.\n * @param {object} customGobos An object where gobo resources not included in QLC+ can be added to.\n */\nasync function addCapabilityLegacyAttributes(xmlCapability, capability, customGobos) {\n  if (capability.colors !== null && capability.colors.allColors.length <= 2) {\n    xmlCapability.attribute('Color', capability.colors.allColors[0]);\n\n    if (capability.colors.allColors.length > 1) {\n      xmlCapability.attribute('Color2', capability.colors.allColors[1]);\n    }\n  }\n\n  const goboResource = await exportHelpers.getGoboResource(capability);\n  if (goboResource) {\n    xmlCapability.attribute('Res', goboResource);\n\n    if (goboResource.startsWith('ofl/')) {\n      customGobos[goboResource] = capability.wheelSlot[0].resource;\n    }\n  }\n}\n\n/**\n * @param {object} xmlCapability The xmlbuilder <Capability> object.\n * @param {Capability} capability The OFL capability object.\n * @returns {boolean} True when one or more <Alias> elements were added to the capability, false otherwise.\n */\nfunction addCapabilityAliases(xmlCapability, capability) {\n  const fixture = capability._channel.fixture;\n\n  let aliasAdded = false;\n  for (const alias of Object.keys(capability.switchChannels)) {\n    const switchingChannel = fixture.getChannelByKey(alias);\n    const defaultChannel = switchingChannel.defaultChannel;\n    const switchedChannel = fixture.getChannelByKey(capability.switchChannels[alias]);\n\n    if (defaultChannel === switchedChannel) {\n      continue;\n    }\n\n    const modesContainingSwitchingChannel = fixture.modes.filter(\n      (mode) => mode.getChannelIndex(switchingChannel.key) !== -1,\n    );\n\n    for (const mode of modesContainingSwitchingChannel) {\n      aliasAdded = true;\n      xmlCapability.element({\n        Alias: {\n          '@Mode': mode.name,\n          '@Channel': defaultChannel.uniqueName,\n          '@With': switchedChannel.uniqueName,\n        },\n      });\n    }\n  }\n\n  return aliasAdded;\n}\n\n/**\n * @param {object} xml The xmlbuilder <FixtureDefinition> object.\n * @param {Mode} mode The OFL mode object.\n * @param {boolean} createPhysical Whether to add a Physical XML element to the mode.\n */\nfunction addMode(xml, mode, createPhysical) {\n  const xmlMode = xml.element({\n    Mode: {\n      '@Name': mode.name,\n    },\n  });\n\n  if (createPhysical) {\n    addPhysical(xmlMode, mode.physical || new Physical({}), mode.fixture, mode);\n  }\n\n  for (const [index, channel] of mode.channels.entries()) {\n    const uniqueName = channel instanceof SwitchingChannel\n      ? channel.defaultChannel.uniqueName\n      : channel.uniqueName;\n\n    xmlMode.element({\n      Channel: {\n        '@Number': index,\n        '#text': uniqueName,\n      },\n    });\n  }\n\n  if (mode.fixture.matrix !== null) {\n    addHeads(xmlMode, mode);\n  }\n}\n\n/**\n * @param {object} xmlParentNode The xmlbuilder object where <Physical> should be added (<FixtureDefinition> or <Mode>).\n * @param {Physical} physical The OFL physical object.\n * @param {Fixture} fixture The OFL fixture object.\n * @param {Mode | null} mode The OFL mode object this physical data section belongs to. Only provide this if panMax and tiltMax should be read from this mode's Pan / Tilt channels, otherwise they are read from all channels.\n */\nfunction addPhysical(xmlParentNode, physical, fixture, mode) {\n  const panMax = getPanTiltMax('Pan', mode?.channels ?? fixture.coarseChannels);\n  const tiltMax = getPanTiltMax('Tilt', mode?.channels ?? fixture.coarseChannels);\n\n  if (Object.keys(physical.jsonObject).length === 0 && panMax === 0 && tiltMax === 0) {\n    // empty physical data\n    return;\n  }\n\n  const physicalSections = {\n    Bulb: () => ({\n      Type: physical.bulbType || 'Other',\n      Lumens: Math.round(physical.bulbLumens) || 0,\n      ColourTemperature: Math.round(physical.bulbColorTemperature) || 0,\n    }),\n    Dimensions: () => ({\n      Weight: physical.weight || 0,\n      Width: Math.round(physical.width) || 0,\n      Height: Math.round(physical.height) || 0,\n      Depth: Math.round(physical.depth) || 0,\n    }),\n    Lens: () => ({\n      Name: physical.lensName || 'Other',\n      DegreesMin: physical.lensDegreesMin || 0,\n      DegreesMax: physical.lensDegreesMax || 0,\n    }),\n    Focus: () => {\n      const focusTypeConditions = {\n        Mirror: fixture.categories.includes('Scanner'),\n        Barrel: fixture.categories.includes('Barrel Scanner'),\n        Head: fixture.categories.includes('Moving Head') || panMax > 0 || tiltMax > 0,\n        Fixed: true,\n      };\n      const focusType = Object.keys(focusTypeConditions).find((type) => focusTypeConditions[type] === true);\n\n      return {\n        Type: focusType,\n        PanMax: panMax,\n        TiltMax: tiltMax,\n      };\n    },\n    Layout: () => {\n      if (fixture.matrix === null) {\n        return undefined;\n      }\n\n      return {\n        Width: fixture.matrix.pixelCountX,\n        Height: fixture.matrix.pixelCountY * fixture.matrix.pixelCountZ,\n      };\n    },\n    Technical: () => {\n      if (physical.DMXconnector === null && physical.power === null) {\n        return undefined;\n      }\n\n      // add whitespace\n      let connector = physical.DMXconnector;\n\n      switch (connector) {\n        case '3.5mm stereo jack': {\n          connector = '3.5 mm stereo jack';\n          break;\n        }\n        case '3-pin XLR IP65': {\n          connector = '3-pin IP65';\n          break;\n        }\n        case '5-pin XLR IP65': {\n          connector = '5-pin IP65';\n          break;\n        }\n        case 'RJ45': {\n          connector = 'Other';\n          break;\n        }\n      }\n\n      return {\n        DmxConnector: connector || 'Other',\n        PowerConsumption: Math.round(physical.power) || 0,\n      };\n    },\n  };\n\n  const physicalSectionProperties = Object.entries(physicalSections)\n    .map(([name, getProperties]) => [name, getProperties()])\n    .filter(([name, properties]) => properties !== undefined);\n\n  const xmlPhysical = xmlParentNode.element('Physical');\n  for (const [name, properties] of physicalSectionProperties) {\n    xmlPhysical.element(name, properties);\n  }\n}\n\n/**\n * @param {'Pan' | 'Tilt'} panOrTilt Whether to return pan max or tilt max.\n * @param {CoarseChannel[]} channels The channels in which to look for pan/tilt angles, e.g. all mode channels.\n * @returns {number} The maximum pan/tilt range in the given channels, i.e. highest angle - lowest angle. If only continous pan/tilt is used, the return value is 9999. Defaults to 0.\n */\nfunction getPanTiltMax(panOrTilt, channels) {\n  const capabilities = channels.flatMap((channel) => channel.capabilities || []);\n\n  const panTiltCapabilities = capabilities.filter((capability) => capability.type === panOrTilt && capability.angle[0].unit === 'deg');\n  const minAngle = Math.min(...panTiltCapabilities.map((capability) => Math.min(capability.angle[0].number, capability.angle[1].number)));\n  const maxAngle = Math.max(...panTiltCapabilities.map((capability) => Math.max(capability.angle[0].number, capability.angle[1].number)));\n  const panTiltMax = maxAngle - minAngle;\n\n  if (panTiltMax === Number.NEGATIVE_INFINITY) {\n    const hasContinuousCapability = capabilities.some((capability) => capability.type === `${panOrTilt}Continuous`);\n    if (hasContinuousCapability) {\n      return 9999;\n    }\n\n    return 0;\n  }\n\n  return Math.round(panTiltMax);\n}\n\n/**\n * Adds Head tags for all used pixels in the given mode, ordered by XYZ direction (pixel groups by appearance in JSON).\n * @param {XMLElement} xmlMode The Mode tag to which the Head tags should be added\n * @param {Mode} mode The fixture's mode whose pixels should be determined.\n */\nfunction addHeads(xmlMode, mode) {\n  const hasMatrixChannels = mode.channels.some(\n    (channel) => channel.pixelKey !== null || (channel instanceof SwitchingChannel && channel.defaultChannel.pixelKey !== null),\n  );\n\n  if (hasMatrixChannels) {\n    const pixelKeys = mode.fixture.matrix.getPixelKeysByOrder('X', 'Y', 'Z');\n    for (const pixelKey of pixelKeys) {\n      const channels = mode.channels.filter((channel) => controlsPixelKey(channel, pixelKey));\n      const xmlHead = xmlMode.element('Head');\n\n      for (const channel of channels) {\n        xmlHead.element({\n          Channel: mode.getChannelIndex(channel.key),\n        });\n      }\n    }\n  }\n\n  /**\n   * @param {AbstractChannel} channel A channel from a mode's channel list.\n   * @param {string} pixelKey The pixel to check for.\n   * @returns {boolean} Whether the given channel controls the given pixel key, either directly or as part of a pixel group.\n   */\n  function controlsPixelKey(channel, pixelKey) {\n    if (channel instanceof SwitchingChannel) {\n      channel = channel.defaultChannel;\n    }\n\n    if (channel.pixelKey !== null) {\n      if (mode.fixture.matrix.pixelGroupKeys.includes(channel.pixelKey)) {\n        return mode.fixture.matrix.pixelGroups[channel.pixelKey].includes(pixelKey);\n      }\n\n      return channel.pixelKey === pixelKey;\n    }\n\n    return false;\n  }\n}\n\n/**\n * Determines the QLC+ fixture type out of the fixture's categories.\n * @param {Fixture} fixture The Fixture instance whose QLC+ type has to be determined.\n * @returns {string} The first of the fixture's categories that is supported by QLC+, defaults to 'Other'.\n */\nfunction getFixtureType(fixture) {\n  const replaceCategories = {\n    'Barrel Scanner': 'Scanner',\n\n    // see https://github.com/OpenLightingProject/open-fixture-library/issues/581\n    'Pixel Bar': isBeamBar() ? 'LED Bar (Beams)' : 'LED Bar (Pixels)',\n  };\n  const ignoredCategories = new Set(['Blinder', 'Matrix', 'Stand']);\n\n  return fixture.categories.map(\n    (category) => replaceCategories[category] ?? category,\n  ).find(\n    (category) => !ignoredCategories.has(category),\n  ) || 'Other';\n\n  /**\n   * @returns {boolean} True if there are individual beams (or it can not be determined), false if the pixels' colors blend into each other.\n   */\n  function isBeamBar() {\n    if (!fixture.physical || !fixture.physical.matrixPixelsSpacing) {\n      return true;\n    }\n\n    return fixture.physical.matrixPixelsSpacing.some((spacing) => spacing !== 0);\n  }\n}\n\n/**\n * Converts a channel's type into a valid QLC+ channel type.\n * @param {string} type Our own OFL channel type.\n * @returns {string} The corresponding QLC+ channel type.\n */\nfunction getChannelType(type) {\n  const qlcplusChannelTypes = {\n    Intensity: ['Intensity', 'Single Color'],\n    Colour: ['Multi-Color'],\n    Pan: ['Pan'],\n    Tilt: ['Tilt'],\n    Beam: ['Focus', 'Zoom', 'Iris', 'Color Temperature'],\n    Gobo: ['Gobo'],\n    Prism: ['Prism'],\n    Shutter: ['Shutter', 'Strobe'],\n    Speed: ['Speed'],\n    Effect: ['Effect', 'Fog'],\n    Maintenance: ['Maintenance'],\n    Nothing: ['NoFunction'],\n  };\n\n  for (const qlcplusType of Object.keys(qlcplusChannelTypes)) {\n    if (qlcplusChannelTypes[qlcplusType].includes(type)) {\n      return qlcplusType;\n    }\n  }\n  return 'Effect'; // default if new types are added to OFL\n}\n"
  },
  {
    "path": "plugins/qlcplus_4.12.2/exportTests/fixture-tool-validation.js",
    "content": "import { execFile as execFileAsync } from 'child_process';\nimport { mkdir, mkdtemp, writeFile } from 'fs/promises';\nimport https from 'https';\nimport os from 'os';\nimport path from 'path';\nimport { promisify } from 'util';\nimport importJson from '../../../lib/import-json.js';\n\nconst execFile = promisify(execFileAsync);\n\nconst GITHUB_BASE_URL = 'https://raw.githubusercontent.com/mcallegari/qlcplus/master/';\nconst FIXTURE_TOOL_DIR_PREFIX = path.join(os.tmpdir(), 'ofl-qlcplus5-fixture-tool-');\nconst FIXTURE_TOOL_PATH = 'resources/fixtures/scripts/fixtures-tool.py';\nconst COLOR_FILTERS_PATH = 'resources/colorfilters/namedrgb.qxcf';\nconst EXPORTED_FIXTURE_PATH = 'resources/fixtures/manufacturer/fixture.qxf';\n\n/**\n * @typedef {object} ExportFile\n * @property {string} name File name, may include slashes to provide a folder structure.\n * @property {string} content File content.\n * @property {string} mimetype File mime type.\n * @property {Fixture[] | null} fixtures Fixture objects that are described in given file; may be omitted if the file doesn't belong to any fixture (e.g. manufacturer information).\n * @property {string | null} mode Mode's shortName if given file only describes a single mode.\n */\n\n/**\n * @param {ExportFile} exportFile The file returned by the plugins' export module.\n * @param {ExportFile[]} allExportFiles An array of all export files.\n * @returns {Promise<void, string[] | string>} Resolve when the test passes or reject with an array of errors or one error if the test fails.\n */\nexport default async function testFixtureToolValidation(exportFile, allExportFiles) {\n  if (exportFile.name.startsWith('gobos/')) {\n    return;\n  }\n\n  // create a unique temporary directory to avoid race conditions when multiple running tests access the same files\n  const directory = await mkdtemp(FIXTURE_TOOL_DIR_PREFIX);\n\n  // download fixtures-tool.py into fixtures/scripts directory\n  const fixtureToolPath = path.resolve(directory, FIXTURE_TOOL_PATH);\n  await mkdir(path.dirname(fixtureToolPath), { recursive: true });\n  const fixtureToolContent = await downloadFile(GITHUB_BASE_URL + FIXTURE_TOOL_PATH);\n  await writeFile(fixtureToolPath, fixtureToolContent, { mode: 0o755 });\n\n  // download namedrgb.qxcf into colorfilters directory\n  const colorFiltersPath = path.resolve(directory, COLOR_FILTERS_PATH);\n  await mkdir(path.dirname(colorFiltersPath), { recursive: true });\n  const namedRgbContent = await downloadFile(GITHUB_BASE_URL + COLOR_FILTERS_PATH);\n  await writeFile(colorFiltersPath, namedRgbContent);\n\n  // write exported fixture.qxf into fixtures/manufacturer directory\n  await mkdir(path.join(directory, 'resources/fixtures/manufacturer'), { recursive: true });\n  await writeFile(path.join(directory, EXPORTED_FIXTURE_PATH), exportFile.content);\n\n  // store used gobos in the gobos/ directory\n  const qlcplusGoboAliases = await importJson('../../../resources/gobos/aliases/qlcplus.json', import.meta.url);\n  const qlcplusGobos = [\n    'gobos/Others/open.svg',\n    'gobos/Others/rainbow.png',\n    ...Object.keys(qlcplusGoboAliases).map((gobo) => `gobos/${gobo}`),\n    ...allExportFiles.filter((file) => file.name.startsWith('gobos/')).map((file) => file.name),\n  ];\n\n  for (const gobo of qlcplusGobos) {\n    const goboPath = path.join(directory, 'resources', gobo);\n    const goboDirectory = path.dirname(goboPath);\n\n    await mkdir(goboDirectory, { recursive: true });\n    await writeFile(goboPath, '');\n  }\n\n  // call the fixture tool\n  const output = await execFile(fixtureToolPath, ['--validate', '.'], {\n    cwd: path.join(directory, 'resources/fixtures'),\n  }).catch((error) => {\n    if (error.stdout) {\n      return {\n        stdout: error.stdout,\n        stderr: error.stderr,\n      };\n    }\n    throw error;\n  });\n\n  const lastLine = output.stdout.split('\\n').findLast((line) => line !== '');\n\n  if (lastLine !== '1 definitions processed. 0 errors detected') {\n    throw output.stdout;\n  }\n}\n\n/**\n * @param {string} url The URL to download the file from.\n * @returns {Promise<string>} A Promise that resolves to the downloaded file's content.\n */\nfunction downloadFile(url) {\n  return new Promise((resolve, reject) => {\n    https.get(url, (response) => {\n      let data = '';\n      response.on('data', (chunk) => {\n        data += chunk;\n      });\n      response.on('end', () => resolve(data));\n    }).on('error', (error) => reject(error));\n  });\n}\n"
  },
  {
    "path": "plugins/qlcplus_4.12.2/exportTests/xsd-schema-conformity.js",
    "content": "import https from 'https';\nimport { XmlDocument, XsdValidator } from 'libxml2-wasm';\n\nconst SCHEMA_URL = 'https://raw.githubusercontent.com/mcallegari/qlcplus/master/resources/schemas/fixture.xsd';\n\n/**\n * @typedef {object} ExportFile\n * @property {string} name File name, may include slashes to provide a folder structure.\n * @property {string} content File content.\n * @property {string} mimetype File mime type.\n * @property {Fixture[] | null} fixtures Fixture objects that are described in given file; may be omitted if the file doesn't belong to any fixture (e.g. manufacturer information).\n * @property {string | null} mode Mode's shortName if given file only describes a single mode.\n */\n\n/**\n * @param {ExportFile} exportFile The file returned by the plugins' export module.\n * @param {ExportFile[]} allExportFiles An array of all export files.\n * @returns {Promise<void, string[] | string>} Resolve when the test passes or reject with an array of errors or one error if the test fails.\n */\nexport default async function testSchemaConformity(exportFile, allExportFiles) {\n  if (exportFile.name.startsWith('gobos/')) {\n    return;\n  }\n\n  const schemaData = await new Promise((resolve, reject) => {\n    https.get(SCHEMA_URL, (response) => {\n      let data = '';\n      response.on('data', (chunk) => {\n        data += chunk;\n      });\n      response.on('end', () => {\n        resolve(data);\n      });\n    });\n  });\n\n  const xsdDocument = XmlDocument.fromString(schemaData);\n  const validator = XsdValidator.fromDoc(xsdDocument);\n  const xmlDocument = XmlDocument.fromString(exportFile.content);\n\n  try {\n    validator.validate(xmlDocument);\n  }\n  catch (error) {\n    throw error.details.map((detail) => detail.message.trim());\n  }\n  finally {\n    validator.dispose();\n    xsdDocument.dispose();\n    xmlDocument.dispose();\n  }\n}\n"
  },
  {
    "path": "plugins/qlcplus_4.12.2/import.js",
    "content": "import xml2js from 'xml2js';\nimport importJson from '../../lib/import-json.js';\nimport {\n  capabilityPresets,\n  getCapabilityFromCapabilityPreset,\n  getCapabilityFromChannelPreset,\n  importHelpers,\n} from './presets.js';\n\nconst qlcplusGoboAliasesPromise = importJson('../../resources/gobos/aliases/qlcplus.json', import.meta.url);\n\nexport const version = '1.1.2';\n\n/**\n * @param {Buffer} buffer The imported file.\n * @param {string} filename The imported file's name.\n * @param {string} authorName The importer's name.\n * @returns {Promise<object, Error>} A Promise resolving to an out object\n */\nexport async function importFixtures(buffer, filename, authorName) {\n  const timestamp = new Date().toISOString().replace(/T.*/, '');\n\n  const warnings = [];\n\n  const fixture = {\n    $schema: 'https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json',\n  };\n\n  const xml = await xml2js.parseStringPromise(buffer.toString());\n\n  const qlcPlusFixture = xml.FixtureDefinition;\n  fixture.name = qlcPlusFixture.Model[0];\n\n  const manufacturerKey = slugify(qlcPlusFixture.Manufacturer[0]);\n  const fixtureKey = `${manufacturerKey}/${slugify(fixture.name)}`;\n\n  const oflManufacturers = await importJson('../../fixtures/manufacturers.json', import.meta.url);\n\n  const manufacturers = {};\n  if (!(manufacturerKey in oflManufacturers)) {\n    manufacturers[manufacturerKey] = {\n      name: qlcPlusFixture.Manufacturer[0],\n    };\n    warnings.push('Please check if manufacturer is correct and add manufacturer URL.');\n  }\n\n  fixture.categories = getOflCategories(qlcPlusFixture);\n\n  const authors = qlcPlusFixture.Creator[0].Author[0].split(/,\\s*/);\n  if (!authors.includes(authorName)) {\n    authors.push(authorName);\n  }\n\n  fixture.meta = {\n    authors,\n    createDate: timestamp,\n    lastModifyDate: timestamp,\n    importPlugin: {\n      plugin: 'qlcplus_4.12.1',\n      date: timestamp,\n      comment: `created by ${qlcPlusFixture.Creator[0].Name[0]} (version ${qlcPlusFixture.Creator[0].Version[0]})`,\n    },\n  };\n\n  if (!('Mode' in qlcPlusFixture)) {\n    qlcPlusFixture.Mode = [];\n  }\n  if (!('Channel' in qlcPlusFixture)) {\n    qlcPlusFixture.Channel = [];\n  }\n\n  addOflFixturePhysical(fixture, qlcPlusFixture);\n\n  fixture.matrix = getOflMatrix(qlcPlusFixture);\n  fixture.wheels = await getOflWheels(qlcPlusFixture);\n  fixture.availableChannels = {};\n  fixture.templateChannels = {};\n\n  for (const channel of qlcPlusFixture.Channel) {\n    addOflChannel(fixture, channel, qlcPlusFixture);\n  }\n\n  mergeFineChannels(fixture, qlcPlusFixture, warnings);\n\n  fixture.modes = qlcPlusFixture.Mode.map((mode) => getOflMode(mode, fixture.physical, warnings));\n\n  addSwitchingChannels(fixture, qlcPlusFixture);\n\n  cleanUpFixture(fixture, qlcPlusFixture);\n\n  return {\n    manufacturers,\n    fixtures: {\n      [fixtureKey]: fixture,\n    },\n    warnings: {\n      [fixtureKey]: warnings,\n    },\n  };\n}\n\n/**\n * @param {object} qlcPlusFixture The QLC+ fixture object.\n * @returns {string[]} The OFL fixture categories.\n */\nfunction getOflCategories(qlcPlusFixture) {\n  const category = qlcPlusFixture.Type[0];\n\n  if (category.startsWith('LED Bar')) {\n    return ['Pixel Bar'];\n  }\n\n  return [category];\n}\n\n/**\n * Adds a global physical object to the OFL fixture object, if necessary.\n * @param {object} fixture The OFL fixture object.\n * @param {object} qlcPlusFixture The QLC+ fixture object.\n */\nfunction addOflFixturePhysical(fixture, qlcPlusFixture) {\n  const allModesHavePhysical = qlcPlusFixture.Mode.every((mode) => 'Physical' in mode);\n  const firstPhysicalMode = qlcPlusFixture.Mode.find((mode) => 'Physical' in mode);\n  const hasModePhysical = firstPhysicalMode !== undefined;\n  const hasGlobalPhysical = 'Physical' in qlcPlusFixture;\n\n  if (hasGlobalPhysical || (hasModePhysical && !allModesHavePhysical)) {\n    fixture.physical = getOflPhysical(hasGlobalPhysical ? qlcPlusFixture.Physical[0] : firstPhysicalMode.Physical[0]);\n\n    if (qlcPlusFixture.Type[0] === 'LED Bar (Pixels)') {\n      fixture.physical.matrixPixels = {\n        spacing: [0, 0, 0],\n      };\n    }\n  }\n}\n\n/**\n * @param {object} qlcPlusFixture The QLC+ fixture object.\n * @returns {object} The OFL matrix object (may be empty).\n */\nfunction getOflMatrix(qlcPlusFixture) {\n  const matrix = {};\n\n  const physicalLayouts = qlcPlusFixture.Mode.concat(qlcPlusFixture)\n    .filter((object) => 'Physical' in object && 'Layout' in object.Physical[0])\n    .map((object) => object.Physical[0].Layout[0]);\n\n  if (physicalLayouts) {\n    const maxWidth = Math.max(...physicalLayouts.map((layout) => Number.parseInt(layout.$.Width, 10)));\n    const maxHeight = Math.max(...physicalLayouts.map((layout) => Number.parseInt(layout.$.Height, 10)));\n\n    matrix.pixelCount = [maxWidth, maxHeight, 1];\n  }\n\n  return matrix;\n}\n\nconst slotTypeFunctions = {\n  Open: {\n    isSlotType: (capability, channelGroup, capabilityPreset) => capability._ === 'Open' || capability.$.Res1 === 'Others/open.svg' || capability.$.Res === 'Others/open.svg',\n    addSlotProperties: (capability, slot) => undefined,\n  },\n  Gobo: {\n    isSlotType: (capability, channelGroup, capabilityPreset) => (capabilityPreset ? capabilityPreset === 'GoboMacro' : channelGroup === 'Gobo'),\n    addSlotProperties: async (capability, slot) => {\n      const goboResource = capability.$.Res1 || capability.$.Res || null;\n      let useResourceName = false;\n\n      if (goboResource) {\n        const qlcplusGoboAliases = await qlcplusGoboAliasesPromise;\n        const goboKey = qlcplusGoboAliases[goboResource];\n\n        if (goboKey) {\n          slot.resource = `gobos/${goboKey}`;\n\n          const resource = await importJson(`../../resources/gobos/${goboKey}.json`, import.meta.url);\n\n          if (resource.name === capability._) {\n            useResourceName = true;\n          }\n        }\n        else {\n          slot.resource = `gobos/aliases/qlcplus/${goboResource}`;\n        }\n      }\n\n      if (!useResourceName) {\n        slot.name = capability._;\n      }\n    },\n  },\n  Color: {\n    isSlotType: (capability, channelGroup, capabilityPreset) => (capabilityPreset ? ['ColorMacro', 'ColorDoubleMacro'].includes(capabilityPreset) : channelGroup === 'Colour'),\n    addSlotProperties: (capability, slot) => {\n      slot.name = capability._;\n\n      const colors = ['Color', 'Color2', 'Res1', 'Res2']\n        .filter((attribute) => attribute in capability.$)\n        .map((attribute) => capability.$[attribute]);\n\n      if (colors.length > 0) {\n        slot.colors = colors;\n      }\n    },\n  },\n  Prism: {\n    isSlotType: (capability, channelGroup, capabilityPreset) => (capabilityPreset ? capabilityPreset === 'PrismEffectOn' : channelGroup === 'Prism'),\n    addSlotProperties: (capability, slot) => {\n      slot.name = capability._;\n\n      if ('Res1' in capability.$) {\n        slot.facets = Number.parseInt(capability.$.Res1, 10);\n      }\n    },\n  },\n\n  // default (has to be the last element!)\n  Unknown: {\n    isSlotType: (capability, channelGroup, capabilityPreset) => true,\n    addSlotProperties: (capability, slot) => {\n      slot.name = capability._;\n    },\n  },\n};\n\n/**\n * Try to extract (guessed) wheels from all channels / capabilities.\n * @param {object} qlcPlusFixture The QLC+ fixture object.\n * @returns {Promise<object | undefined>} A Promise that resolves to the OFL wheels object or undefined if there are no wheels.\n */\nasync function getOflWheels(qlcPlusFixture) {\n  const wheels = {};\n\n  const wheelChannels = qlcPlusFixture.Channel.filter((channel) => {\n    const channelName = channel.$.Name;\n\n    const hasGoboPresetCapability = (channel.Capability || []).some(\n      (capability) => ['GoboMacro', 'GoboShakeMacro'].includes(capability.$.Preset),\n    );\n\n    const isWheelChannel = /wheel\\b/i.test(channelName) || hasGoboPresetCapability;\n    const isRotationChannel = /rotation|index/i.test(channelName) || ('Group' in channel && channel.Group[0]._ === 'Speed');\n\n    return isWheelChannel && !isRotationChannel;\n  });\n\n  for (const channel of wheelChannels) {\n    wheels[channel.$.Name] = {\n      slots: await getSlots(channel),\n    };\n  }\n\n  return Object.keys(wheels).length > 0 ? wheels : undefined;\n\n  /**\n   * @param {object} qlcPlusChannel The QLC+ channel object.\n   * @returns {Promise<object[]>} A Promise that resolves to an array of OFL slot objects.\n   */\n  async function getSlots(qlcPlusChannel) {\n    const slots = [];\n\n    for (const capability of (qlcPlusChannel.Capability || [])) {\n      if (/\\bc?cw\\b|rainbow|stop|(?:counter|anti)?[ -]?clockwise|rotat|spin/i.test(capability._)) {\n        // skip rotation capabilities\n        continue;\n      }\n\n      const capabilityPreset = capability.$.Preset || '';\n\n      if (/^(?:GoboShakeMacro|ColorWheelIndex)$|^Rotation/.test(capabilityPreset)) {\n        continue;\n      }\n\n      const foundSlotType = Object.keys(slotTypeFunctions).find(\n        (slotType) => slotTypeFunctions[slotType].isSlotType(capability, qlcPlusChannel.Group[0]._, capabilityPreset),\n      );\n\n      const slot = {\n        type: foundSlotType,\n      };\n\n      await slotTypeFunctions[foundSlotType].addSlotProperties(capability, slot);\n\n      slots.push(slot);\n    }\n\n    return slots;\n  }\n}\n\nconst parserPerChannelType = {\n  Nothing: () => ({\n    type: 'NoFunction',\n  }),\n  Intensity: ({ qlcPlusChannel, capabilityName }) => {\n    const capability = {};\n\n    if ('Colour' in qlcPlusChannel && qlcPlusChannel.Colour[0] !== 'Generic') {\n      capability.type = 'ColorIntensity';\n      capability.color = qlcPlusChannel.Colour[0];\n    }\n    else {\n      capability.type = 'Intensity';\n    }\n\n    if (!/^(?:intensity|dimmer)$/i.test(capabilityName)) {\n      capability.comment = capabilityName;\n    }\n\n    return capability;\n  },\n  Colour: ({ channelName, qlcPlusCapability, capabilityName, index }) => {\n    const capability = {};\n\n    if (/wheel\\b/i.test(channelName)) {\n      capability.type = 'WheelSlot';\n      capability.slotNumber = index + 1;\n\n      capability.comment = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n      if ('speed' in capability || 'speedStart' in capability) {\n        capability.type = 'WheelRotation';\n        delete capability.slotNumber;\n      }\n\n      return capability;\n    }\n\n    capability.type = 'ColorPreset';\n    capability.comment = capabilityName;\n\n    if ('Color' in qlcPlusCapability.$) {\n      capability.colors = [qlcPlusCapability.$.Color];\n\n      if ('Color2' in qlcPlusCapability.$) {\n        capability.colors.push(qlcPlusCapability.$.Color2);\n      }\n    }\n\n    return capability;\n  },\n  Gobo: ({ capabilityName, channelNameInWheels, index }) => {\n    if (/shake\\b|shaking\\b/i.test(capabilityName)) {\n      return capabilityPresets.GoboShakeMacro.importCapability({ capabilityName, index });\n    }\n\n    const capability = {\n      type: 'WheelSlot',\n      slotNumber: index + 1,\n    };\n\n    capability.comment = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n    if ('speed' in capability || 'speedStart' in capability) {\n      capability.type = channelNameInWheels ? 'WheelRotation' : 'WheelSlotRotation';\n      delete capability.slotNumber;\n    }\n\n    return capability;\n  },\n  Effect: ({ capabilityName }) => {\n    const capability = {\n      type: 'Effect',\n      effectName: '', // set it first here so effectName is before speedStart/speedEnd\n    };\n    capability.effectName = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n    if (capability.effectName === '') {\n      delete capability.effectName;\n      if (capability.type === 'Effect') {\n        capability.type = 'Speed';\n      }\n    }\n    else if (capability.type === 'Rotation') {\n      capability.comment = capability.effectName;\n      delete capability.effectName;\n    }\n    else if (/\\bsound\\b/i.test(capability.effectName)) {\n      capability.soundControlled = true;\n    }\n\n    return capability;\n  },\n  Maintenance: ({ capabilityName }) => ({\n    type: 'Maintenance',\n    comment: capabilityName,\n  }),\n  Pan: ({ channelName, capabilityName, panMax }) => {\n    if (/continuous/i.test(channelName)) {\n      const capability = {\n        type: 'PanContinuous',\n      };\n      capability.comment = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n      if (!('speed' in capability || 'speedStart' in capability)) {\n        capability.speedStart = 'slow CW';\n        capability.speedEnd = 'fast CW';\n        capability.helpWanted = 'Are the automatically added speed values correct?';\n      }\n\n      return capability;\n    }\n\n    return Object.assign(importHelpers.getPanTiltCap('Pan', panMax), {\n      comment: capabilityName,\n    });\n  },\n  Tilt: ({ channelName, capabilityName, tiltMax }) => {\n    if (/continuous/i.test(channelName)) {\n      const capability = {\n        type: 'TiltContinuous',\n      };\n      capability.comment = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n      if (!('speed' in capability || 'speedStart' in capability)) {\n        capability.speedStart = 'slow CW';\n        capability.speedEnd = 'fast CW';\n        capability.helpWanted = 'Are the automatically added speed values correct?';\n      }\n\n      return capability;\n    }\n\n    return Object.assign(importHelpers.getPanTiltCap('Tilt', tiltMax), {\n      comment: capabilityName,\n    });\n  },\n  Prism: ({ capabilityName }) => ({\n    type: 'Prism',\n    comment: capabilityName,\n  }),\n  Shutter: ({ capabilityName }) => {\n    const capability = {\n      type: 'ShutterStrobe',\n    };\n\n    const shutterEffects = {\n      Closed: /^(?:blackout|(?:shutter |strobe )?closed?)$/i,\n      Open: /^(?:(?:shutter |strobe )?open|full?)$/i,\n      Pulse: /puls/i,\n      RampUp: /ramp\\s*up/i,\n      RampDown: /ramp\\s*down/i,\n    };\n\n    capability.shutterEffect = Object.keys(shutterEffects).find(\n      (shutterEffect) => capabilityName.match(shutterEffects[shutterEffect]),\n    ) || 'Strobe';\n\n    if (['Open', 'Closed'].includes(capability.shutterEffect)) {\n      // short circuit, there's no need to test for randomTiming or speed\n      return capability;\n    }\n\n    if (/random/i.test(capabilityName)) {\n      capability.randomTiming = true;\n    }\n\n    capability.comment = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n    if (!('speed' in capability || 'speedStart' in capability)) {\n      capability.speedStart = 'slow';\n      capability.speedEnd = 'fast';\n      capability.helpWanted = 'Are the automatically added speed values correct?';\n    }\n\n    return capability;\n  },\n  Speed: ({ channelName, capabilityName }) => {\n    const capability = {};\n\n    if (/pan\\/?tilt/i.test(channelName)) {\n      capability.type = 'PanTiltSpeed';\n    }\n    else if (/strobe/i.test(channelName) || /strobe/i.test(capabilityName)) {\n      if (/speed|rate/i.test(channelName)) {\n        capability.type = 'StrobeSpeed';\n      }\n      else {\n        capability.type = 'ShutterStrobe';\n        capability.shutterEffect = 'Strobe';\n      }\n    }\n    else {\n      capability.type = 'Speed';\n    }\n\n    capability.comment = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n    if (!('speed' in capability || 'speedStart' in capability)) {\n      capability.speedStart = 'slow';\n      capability.speedEnd = 'fast';\n      capability.helpWanted = 'Are the automatically added speed values correct?';\n    }\n\n    return capability;\n  },\n};\n\n/**\n * Adds a QLC+ channel to the OFL fixture's availableChannels object.\n * @param {object} fixture The OFL fixture object.\n * @param {object} qlcPlusChannel The QLC+ channel object.\n * @param {object} qlcPlusFixture The QLC+ fixture object.\n */\nfunction addOflChannel(fixture, qlcPlusChannel, qlcPlusFixture) {\n  const channel = {\n    fineChannelAliases: [],\n    dmxValueResolution: '8bit',\n    defaultValue: Number.parseInt(qlcPlusChannel.$.Default, 10) || 0,\n  };\n\n  const physicals = qlcPlusFixture.Mode.concat(qlcPlusFixture)\n    .filter((object) => 'Physical' in object)\n    .map((object) => object.Physical[0]);\n\n  const [panMax, tiltMax] = ['PanMax', 'TiltMax'].map(\n    (property) => Math.max(...physicals.map((physical) => {\n      if (physical.Focus && property in physical.Focus[0].$) {\n        return Number.parseInt(physical.Focus[0].$[property], 10) || 0;\n      }\n      return 0;\n    })),\n  );\n\n  const channelName = qlcPlusChannel.$.Name;\n  const channelPreset = qlcPlusChannel.$.Preset;\n\n  if (channelPreset) {\n    channel.capabilities = [getCapabilityFromChannelPreset(channelPreset, channelName, panMax, tiltMax)];\n  }\n  else if ('Capability' in qlcPlusChannel) {\n    channel.capabilities = qlcPlusChannel.Capability.map(\n      (capability) => getOflCapability(capability),\n    );\n  }\n  else {\n    channel.capabilities = [getOflCapability({\n      _: '0-100%',\n      $: {\n        Min: '0',\n        Max: '255',\n      },\n    })];\n  }\n\n  fixture.availableChannels[channelName] = channel;\n\n  /**\n   * @param {object} qlcPlusCapability The QLC+ capability object.\n   * @returns {object} The OFL capability object.\n   */\n  function getOflCapability(qlcPlusCapability) {\n    const capability = {\n      dmxRange: [Number.parseInt(qlcPlusCapability.$.Min, 10), Number.parseInt(qlcPlusCapability.$.Max, 10)],\n      type: '',\n    };\n\n    const trimmedChannelName = qlcPlusChannel.$.Name.trim();\n    const channelType = qlcPlusChannel.Group[0]._;\n    const capabilityName = (qlcPlusCapability._ || '').trim();\n\n    const capabilityData = {\n      qlcPlusChannel,\n      channelName: trimmedChannelName,\n      channelType,\n      channelNameInWheels: trimmedChannelName in (fixture.wheels || {}),\n      qlcPlusCapability,\n      capabilityName,\n      index: qlcPlusChannel.Capability?.indexOf(qlcPlusCapability) ?? 0,\n      res1: qlcPlusCapability.$.Res1,\n      res2: qlcPlusCapability.$.Res2,\n      panMax,\n      tiltMax,\n    };\n\n    const capabilityPreset = qlcPlusCapability.$.Preset;\n\n    if (capabilityPreset && capabilityPreset !== 'Alias') {\n      Object.assign(capability, getCapabilityFromCapabilityPreset(capabilityPreset, capabilityData));\n    }\n    else if (/^(?:nothing|no func(?:tion)?|unused|not used|empty|no strobe|no prism|no frost)$/i.test(capabilityName)) {\n      capability.type = 'NoFunction';\n    }\n    else if (channelType in parserPerChannelType) {\n      // try to parse capability based on channel type\n      Object.assign(capability, parserPerChannelType[channelType](capabilityData));\n    }\n    else {\n      capability.type = 'Generic';\n      capability.comment = capabilityName;\n    }\n\n    deleteCommentIfUnnecessary();\n\n    return capability;\n\n    /**\n     * Deletes the capability's comment if it adds no valuable information.\n     */\n    function deleteCommentIfUnnecessary() {\n      if (!('comment' in capability)) {\n        return;\n      }\n\n      const zeroToHundredRegex = /^0%?\\s*(?:-|to|–|…|\\.{2,}|->|<->|→)\\s*100%$/i;\n\n      if (capability.comment === trimmedChannelName || capability.comment.length === 0 || zeroToHundredRegex.test(capability.comment)) {\n        delete capability.comment;\n      }\n    }\n  }\n}\n\n/**\n * @param {object} qlcPlusPhysical The QLC+ mode's physical object.\n * @param {object | undefined} [oflFixturePhysical={}] The OFL fixture's physical object.\n * @returns {object} The OFL mode's physical object.\n */\nfunction getOflPhysical(qlcPlusPhysical, oflFixturePhysical = {}) {\n  const physical = {};\n\n  addDimensions();\n  addTechnical();\n\n  if ('Bulb' in qlcPlusPhysical) {\n    addBulb();\n  }\n\n  if ('Lens' in qlcPlusPhysical) {\n    addLens();\n  }\n\n  for (const section of ['bulb', 'lens']) {\n    if (JSON.stringify(physical[section]) === '{}') {\n      delete physical[section];\n    }\n  }\n\n  return physical;\n\n  /**\n   * Handles the Dimensions section.\n   */\n  function addDimensions() {\n    if (!('Dimensions' in qlcPlusPhysical)) {\n      return;\n    }\n\n    const width = Number.parseFloat(qlcPlusPhysical.Dimensions[0].$.Width);\n    const height = Number.parseFloat(qlcPlusPhysical.Dimensions[0].$.Height);\n    const depth = Number.parseFloat(qlcPlusPhysical.Dimensions[0].$.Depth);\n    const weight = Number.parseFloat(qlcPlusPhysical.Dimensions[0].$.Weight);\n\n    const dimensionsArray = [width, height, depth];\n\n    if (width + height + depth !== 0 && JSON.stringify(dimensionsArray) !== JSON.stringify(oflFixturePhysical.dimensions)) {\n      physical.dimensions = dimensionsArray;\n    }\n\n    if (weight !== 0 && oflFixturePhysical.weight !== weight) {\n      physical.weight = weight;\n    }\n  }\n\n  /**\n   * Handles the Technical section.\n   */\n  function addTechnical() {\n    if (!('Technical' in qlcPlusPhysical)) {\n      return;\n    }\n\n    const power = Number.parseFloat(qlcPlusPhysical.Technical[0].$.PowerConsumption);\n    if (power !== 0 && oflFixturePhysical.power !== power) {\n      physical.power = power;\n    }\n\n    let DMXconnector = qlcPlusPhysical.Technical[0].$.DmxConnector;\n\n    // remove whitespace\n    if (DMXconnector === '3.5 mm stereo jack') {\n      DMXconnector = '3.5mm stereo jack';\n    }\n\n    if (!['', 'Other', oflFixturePhysical.DMXconnector].includes(DMXconnector)) {\n      physical.DMXconnector = DMXconnector;\n    }\n  }\n\n  /**\n   * Handles the Bulb section.\n   */\n  function addBulb() {\n    physical.bulb = {};\n\n    const type = qlcPlusPhysical.Bulb[0].$.Type;\n    if (!['', 'Other', getOflFixturePhysicalProperty('bulb', 'type')].includes(type)) {\n      physical.bulb.type = type;\n    }\n\n    const colorTemperature = Number.parseFloat(qlcPlusPhysical.Bulb[0].$.ColourTemperature);\n    if (colorTemperature && getOflFixturePhysicalProperty('bulb', 'colorTemperature') !== colorTemperature) {\n      physical.bulb.colorTemperature = colorTemperature;\n    }\n\n    const lumens = Number.parseFloat(qlcPlusPhysical.Bulb[0].$.Lumens);\n    if (lumens && getOflFixturePhysicalProperty('bulb', 'lumens') !== lumens) {\n      physical.bulb.lumens = lumens;\n    }\n  }\n\n  /**\n   * Handles the Lens section.\n   */\n  function addLens() {\n    physical.lens = {};\n\n    const name = qlcPlusPhysical.Lens[0].$.Name;\n    if (!['', 'Other', getOflFixturePhysicalProperty('lens', 'name')].includes(name)) {\n      physical.lens.name = name;\n    }\n\n    const degMin = Number.parseFloat(qlcPlusPhysical.Lens[0].$.DegreesMin);\n    const degMax = Number.parseFloat(qlcPlusPhysical.Lens[0].$.DegreesMax);\n    const degreesMinMax = [degMin, degMax];\n\n    if ((degMin !== 0 || degMax !== 0)\n      && (JSON.stringify(getOflFixturePhysicalProperty('lens', 'degreesMinMax')) !== JSON.stringify(degreesMinMax))) {\n      physical.lens.degreesMinMax = degreesMinMax;\n    }\n  }\n\n  /**\n   * Helper function to get data from the OFL fixture's physical data.\n   * @param {string} section The section object property name.\n   * @param {string} property The property name in the section,\n   * @returns {unknown} The property data, or undefined.\n   */\n  function getOflFixturePhysicalProperty(section, property) {\n    if (!(section in oflFixturePhysical)) {\n      return undefined;\n    }\n\n    return oflFixturePhysical[section][property];\n  }\n}\n\n/**\n * @param {object} qlcPlusMode The QLC+ mode object.\n * @param {object | undefined} oflFixturePhysical The OFL fixture's physical object.\n * @param {string[]} warningsArray This fixture's warnings array in the `out` object.\n * @returns {object} The OFL mode object.\n */\nfunction getOflMode(qlcPlusMode, oflFixturePhysical, warningsArray) {\n  const mode = {\n    name: qlcPlusMode.$.Name.replaceAll(/\\s+mode|mode\\s+/gi, ''),\n  };\n\n  const match = mode.name.match(/(\\d+)(?:\\s+|-|)(?:channels?|chan|ch)/i);\n  if (match) {\n    const [matchedPart, numberOfChannels] = match;\n    mode.shortName = mode.name.replace(matchedPart, `${numberOfChannels}ch`);\n    mode.name = mode.name.replace(matchedPart, `${numberOfChannels}-channel`);\n  }\n\n  if ('Physical' in qlcPlusMode) {\n    const physical = getOflPhysical(qlcPlusMode.Physical[0], oflFixturePhysical);\n\n    if (JSON.stringify(physical) !== '{}') {\n      mode.physical = physical;\n    }\n  }\n\n  mode.channels = [];\n  for (const channel of (qlcPlusMode.Channel || [])) {\n    mode.channels[Number.parseInt(channel.$.Number, 10)] = channel._;\n  }\n\n  addHeadWarnings(qlcPlusMode, mode, warningsArray);\n\n  return mode;\n}\n\n/**\n * @param {object} qlcPlusMode The QLC+ mode object.\n * @param {object} mode The corresponding OFL mode object.\n * @param {string[]} warningsArray This fixture's warnings array in the `out` object.\n */\nfunction addHeadWarnings(qlcPlusMode, mode, warningsArray) {\n  if ('Head' in qlcPlusMode) {\n    for (const [index, head] of qlcPlusMode.Head.entries()) {\n      if (head.Channel === undefined) {\n        continue;\n      }\n\n      const channelList = head.Channel.map((channel) => mode.channels[Number.parseInt(channel, 10)]).join(', ');\n\n      warningsArray.push(`Please add ${mode.name} mode's Head #${index + 1} to the fixture's matrix. The included channels were ${channelList}.`);\n    }\n  }\n}\n\n/**\n * @param {object} fixture The OFL fixture object.\n * @param {object} qlcPlusFixture The QLC+ fixture object.\n * @param {string[]} warningsArray This fixture's warnings array in the `out` object.\n */\nfunction mergeFineChannels(fixture, qlcPlusFixture, warningsArray) {\n  const fineChannelRegex = /\\s*fine\\s*|\\s*16[\\s_-]*bit\\s*/i;\n\n  const fineChannels = qlcPlusFixture.Channel.filter(\n    (channel) => ('Group' in channel && channel.Group[0].$.Byte === '1') || ('Preset' in channel.$ && channel.$.Preset.endsWith('Fine')),\n  );\n\n  for (const qlcPlusFineChannel of fineChannels) {\n    const channelKey = qlcPlusFineChannel.$.Name;\n\n    try {\n      const coarseChannelKey = getCoarseChannelKey(qlcPlusFineChannel);\n      if (!coarseChannelKey) {\n        throw new Error('The corresponding coarse channel could not be detected.');\n      }\n\n      fixture.availableChannels[coarseChannelKey].fineChannelAliases.push(channelKey);\n\n      const fineChannel = fixture.availableChannels[channelKey];\n      if (fineChannel.capabilities.length > 1) {\n        throw new Error(`Merge its capabilities into channel '${coarseChannelKey}'.`);\n      }\n\n      delete fixture.availableChannels[channelKey];\n    }\n    catch (error) {\n      warningsArray.push(`Please check 16bit channel '${channelKey}': ${error.message}`);\n    }\n  }\n\n  /**\n   * @param {string} qlcPlusFineChannel The key of the fine channel.\n   * @returns {string | null} The key of the corresponding coarse channel, or null if it could not be detected.\n   */\n  function getCoarseChannelKey(qlcPlusFineChannel) {\n    const fineChannelKey = qlcPlusFineChannel.$.Name;\n\n    // try deducing coarse channel from fine channel preset\n    if ('Preset' in qlcPlusFineChannel.$) {\n      const coarseChannelPreset = qlcPlusFineChannel.$.Preset.slice(0, -4);\n\n      const coarseChannels = qlcPlusFixture.Channel.filter(\n        (coarseChannel) => coarseChannel.$.Preset === coarseChannelPreset,\n      );\n      if (coarseChannels.length === 1) {\n        return coarseChannels[0].$.Name;\n      }\n    }\n\n    // try deducing coarse channel from fine channel group\n    if ('Group' in qlcPlusFineChannel) {\n      const fineChannelGroupName = qlcPlusFineChannel.Group[0]._;\n\n      const coarseChannels = qlcPlusFixture.Channel.filter((coarseChannel) => {\n        if (!('Group' in coarseChannel)) {\n          return false;\n        }\n\n        const coarseChannelGroupName = coarseChannel.Group[0]._;\n        const coarseChannelGroupByte = coarseChannel.Group[0].$.Byte;\n\n        return coarseChannelGroupName === fineChannelGroupName && coarseChannelGroupByte === '0';\n      });\n\n      if (coarseChannels.length === 1) {\n        return coarseChannels[0].$.Name;\n      }\n    }\n\n    // last option: try deducing coarse channel from fine channel name\n\n    if (!fineChannelRegex.test(fineChannelKey)) {\n      return null;\n    }\n\n    // e.g. \"Pan\" instead of \"Pan Fine\"\n    const coarseChannelKey = fineChannelKey.replace(fineChannelRegex, '');\n\n    return Object.keys(fixture.availableChannels).find(\n      (key) => key === coarseChannelKey || key.replace(fineChannelKey, '').match(/^(?:\\s+|\\s+coarse)$/i),\n    );\n  }\n}\n\n/**\n * Add switchChannels from capability Aliases to channels' capabilities and\n * update the channel keys in modes.\n * @param {object} fixture The OFL fixture object.\n * @param {object} qlcPlusFixture The QCL+ fixture object.\n */\nfunction addSwitchingChannels(fixture, qlcPlusFixture) {\n  for (const qlcPlusChannel of qlcPlusFixture.Channel) {\n    if (!hasAliases(qlcPlusChannel)) {\n      continue;\n    }\n\n    const switchChannels = [];\n    for (const [index, capability] of qlcPlusChannel.Capability.entries()) {\n      for (const alias of (capability.Alias || [])) {\n        const switchChannel = switchChannels.find((channel) => channel.default === alias.$.Channel && channel.modes.includes(alias.$.Mode));\n        if (switchChannel) {\n          switchChannel.switchTo[index] = alias.$.With;\n        }\n        else {\n          switchChannels.push({\n            default: alias.$.Channel,\n            modes: [alias.$.Mode],\n            switchTo: {\n              [index]: alias.$.With,\n            },\n          });\n        }\n      }\n    }\n\n    mergeSimilarSwitchChannels(switchChannels);\n    replaceSwitchingChannelsInModes(switchChannels, fixture.modes);\n    addSwitchChannelsToCapabilities(switchChannels, fixture.availableChannels[qlcPlusChannel.$.Name]);\n  }\n}\n\n/**\n * @param {object} qlcPlusChannel The QLC+ channel object to check.\n * @returns {boolean} True if there is at least one capability with an Alias attribute, false otherwise.\n */\nfunction hasAliases(qlcPlusChannel) {\n  return (qlcPlusChannel.Capability || []).some((capability) => capability.$.Preset === 'Alias');\n}\n\n/**\n * @param {object[]} switchChannels The array of switch channels.\n */\nfunction mergeSimilarSwitchChannels(switchChannels) {\n  for (const [switchChannelIndex, switchChannel] of switchChannels.entries()) {\n    const switchToEntries = Object.entries(switchChannel.switchTo);\n\n    for (let index = switchChannelIndex + 1; index < switchChannels.length; index++) {\n      const otherSwitchChannel = switchChannels[index];\n\n      if (otherSwitchChannel.default !== switchChannel.default) {\n        continue;\n      }\n\n      const otherSwitchTo = otherSwitchChannel.switchTo;\n      const switchToSame = switchToEntries.length === Object.keys(otherSwitchTo).length && switchToEntries.every(\n        ([capabilityIndex, switchToChannel]) => otherSwitchTo[capabilityIndex] === switchToChannel,\n      );\n\n      if (!switchToSame) {\n        continue;\n      }\n\n      switchChannel.modes.push(...otherSwitchChannel.modes);\n      switchChannels.splice(index, 1);\n      index--;\n    }\n\n    const alternatives = new Set([switchChannel.default, ...Object.values(switchChannel.switchTo)]);\n    switchChannel.key = [...alternatives].join(' / ');\n  }\n}\n\n/**\n * Replaces references to all switch channels' default channels with the switch\n * channel itself. If multiple switch channels have the same key, appends the\n * mode names to make them unique.\n * @param {object[]} switchChannels The array of switch channels.\n * @param {object[]} oflModes The array of OFL modes.\n */\nfunction replaceSwitchingChannelsInModes(switchChannels, oflModes) {\n  for (const switchChannel of switchChannels) {\n    const swChannelsWithSameKey = switchChannels.filter((channel) => channel.key === switchChannel.key);\n\n    if (swChannelsWithSameKey.length > 1) {\n      for (const channel of swChannelsWithSameKey) {\n        const channelModes = channel.modes.join(', ');\n        channel.key += ` (${channelModes})`;\n      }\n    }\n\n    const usingModes = oflModes.filter((mode) => switchChannel.modes.includes(mode.name));\n    for (const mode of usingModes) {\n      const index = mode.channels.indexOf(switchChannel.default);\n\n      mode.channels[index] = switchChannel.key;\n    }\n  }\n}\n\n/**\n * @param {object[]} switchChannels The array of switch channels.\n * @param {object} oflTriggerChannel The OFL trigger channel.\n */\nfunction addSwitchChannelsToCapabilities(switchChannels, oflTriggerChannel) {\n  for (const [index, capability] of oflTriggerChannel.capabilities.entries()) {\n    capability.switchChannels = Object.fromEntries(switchChannels.map(\n      (switchChannel) => [switchChannel.key, switchChannel.switchTo[index] || switchChannel.default],\n    ));\n  }\n}\n\n/**\n * @param {object} fixture The OFL fixture object.\n * @param {object} qlcPlusFixture The QCL+ fixture object.\n */\nfunction cleanUpFixture(fixture, qlcPlusFixture) {\n  // delete empty fineChannelAliases arrays and unnecessary dmxValueResolution properties\n  for (const channelKey of Object.keys(fixture.availableChannels)) {\n    const channel = fixture.availableChannels[channelKey];\n\n    if (channel.capabilities.length === 1) {\n      channel.capability = channel.capabilities[0];\n      delete channel.capabilities;\n      delete channel.capability.dmxRange;\n\n      if (!('defaultValue' in channel) || channel.defaultValue === 0) {\n        delete channel.dmxValueResolution;\n      }\n    }\n\n    if (channel.fineChannelAliases.length === 0) {\n      delete channel.fineChannelAliases;\n      delete channel.dmxValueResolution;\n    }\n  }\n\n  const fixtureUsesHeads = qlcPlusFixture.Mode.some((mode) => 'Head' in mode);\n  if (!fixtureUsesHeads) {\n    delete fixture.matrix;\n    delete fixture.templateChannels;\n  }\n}\n\n/**\n * @param {string} string The string to slugify.\n * @returns {string} A slugified version of the string, i.e. only containing lowercase letters, numbers and dashes.\n */\nfunction slugify(string) {\n  return string.toLowerCase().replaceAll(/[^\\da-z-]+/g, ' ').trim().replaceAll(/\\s+/g, '-');\n}\n"
  },
  {
    "path": "plugins/qlcplus_4.12.2/plugin.json",
    "content": "{\n  \"$schema\": \"../../schemas/plugin.json\",\n\n  \"name\": \"QLC+ 4.12.2\",\n  \"previousVersions\": {\n    \"qlcplus\": \"QLC+\",\n    \"qlcplus_4.11.2\": \"QLC+ 4.11.2\",\n    \"qlcplus_4.12.0\": \"QLC+ 4.12.0\",\n    \"qlcplus_4.12.1\": \"QLC+ 4.12.1\"\n  },\n  \"description\": [\n    \"<p><em>Q Light Controller+</em> is a feature-rich open-source lighting\",\n    \"software. This plugin works with QLC+ version 4.12.2 and above.\",\n    \"It is already future-proof for upcoming version 5 (alpha).</p>\"\n  ],\n  \"links\": {\n    \"Website\": \"https://www.qlcplus.org/\",\n    \"Fixture library download\": \"https://github.com/mcallegari/qlcplus/tree/master/resources/fixtures\",\n    \"User fixtures in the forum\": \"https://www.qlcplus.org/forum/viewforum.php?f=3\"\n  },\n  \"fixtureUsage\": [\n    \"<p>Copy the <code>.qxf</code> files into the <code>fixtures</code>\",\n    \"subdirectory of the user library directory.</p>\"\n  ],\n  \"fileLocations\": {\n    \"subDirectoriesAllowed\": false,\n    \"Windows\": {\n      \"main\": \"C:\\\\QLC+\",\n      \"user\": \"C:\\\\Users\\\\[user name]\\\\QLC+\"\n    },\n    \"Mac OS\": {\n      \"main\": \"/Applications/QLC+.app/Contents/Resources\",\n      \"user\": \"~/Library/Application Support/QLC+\"\n    },\n    \"Linux\": {\n      \"main\": \"/usr/share/qlcplus\",\n      \"user\": \"~/.qlcplus\"\n    }\n  }\n}\n"
  },
  {
    "path": "plugins/qlcplus_4.12.2/presets.js",
    "content": "/**\n * @fileoverview Channel and capability presets, together with functions to export or import them.\n */\n\nimport importJson from '../../lib/import-json.js';\n\nconst qlcplusGoboAliasesPromise = importJson('../../resources/gobos/aliases/qlcplus.json', import.meta.url);\n\n// ########## Helper functions ##########\n\nexport const exportHelpers = {\n  isIncreasingSpeed: (capability) => capability.speed !== null && Math.abs(capability.speed[0].number) < Math.abs(capability.speed[1].number),\n  isDecreasingSpeed: (capability) => capability.speed !== null && Math.abs(capability.speed[0].number) > Math.abs(capability.speed[1].number),\n  isStopped: (capability) => capability.speed !== null && capability.speed[0].number === 0 && capability.speed[1].number === 0,\n  isIncreasingDuration: (capability) => capability.duration !== null && Math.abs(capability.duration[0].number) < Math.abs(capability.duration[1].number),\n  isDecreasingDuration: (capability) => capability.duration !== null && Math.abs(capability.duration[0].number) > Math.abs(capability.duration[1].number),\n  isColorIntensity: (capability, color) => capability.type === 'ColorIntensity' && capability.color === color,\n  isShutterEffect: (capability, shutterEffect) => capability.type === 'ShutterStrobe' && capability.shutterEffect === shutterEffect,\n  hasFrequency: (capability) => capability.speed !== null && (capability.speed[0].unit === 'Hz' || capability.speed[0].unit === 'bpm'),\n  isRotationSpeed: (capability) => (capability.type.endsWith('Rotation') || ['PanContinuous', 'TiltContinuous', 'Prism'].includes(capability.type)) && capability.speed !== null,\n  isRotationAngle: (capability) => (capability.type.endsWith('Rotation') || ['Pan', 'Tilt', 'Prism'].includes(capability.type)) && capability.angle !== null,\n  isBeamAngle: (capability) => (capability.type === 'BeamAngle' || capability.type === 'Zoom') && capability.angle !== null,\n  isWheelChannel: (channel) => channel.capabilities.some((capability) => ['WheelSlot', 'WheelRotation'].includes(capability.type)),\n  isAllowedInWheels: (capability) => ['WheelSlot', 'WheelShake', 'WheelSlotRotation', 'WheelRotation', 'Effect', 'NoFunction'].includes(capability.type),\n  getGoboResource: async (capability) => {\n    if (capability.isSlotType('Open')) {\n      return 'Others/open.svg';\n    }\n\n    if (capability.wheelSlot !== null && capability.wheelSlot[0] === capability.wheelSlot[1]) {\n      const resource = capability.wheelSlot[0].resource;\n\n      if (resource) {\n        const qlcplusGoboAliases = await qlcplusGoboAliasesPromise;\n        const qlcplusGoboAlias = Object.keys(qlcplusGoboAliases).find(\n          (alias) => qlcplusGoboAliases[alias] === resource.key,\n        );\n\n        if (qlcplusGoboAlias) {\n          return qlcplusGoboAlias;\n        }\n\n        return `ofl/${resource.key}.${resource.imageExtension}`;\n      }\n    }\n\n    return null;\n  },\n};\n\nexport const importHelpers = {\n  getColorIntensityCap: (color) => ({\n    type: 'ColorIntensity',\n    color,\n  }),\n\n  getPanTiltCap: (panOrTilt, maxValue = 0) => {\n    const capability = {\n      type: panOrTilt,\n      angleStart: '0deg',\n      angleEnd: `${maxValue}deg`,\n    };\n\n    if (maxValue === 0) {\n      capability.angleStart = '0%';\n      capability.angleEnd = '100%';\n      capability.helpWanted = 'Can you provide exact angles?';\n    }\n\n    return capability;\n  },\n\n  getShutterStrobeCap: (shutterEffect, speedStart = '', speedEnd = '', randomTiming = false) => {\n    const capability = {\n      type: 'ShutterStrobe',\n      shutterEffect,\n    };\n\n    if (speedEnd) {\n      capability.speedStart = speedStart;\n      capability.speedEnd = speedEnd;\n    }\n    else if (speedStart) {\n      capability.speed = speedStart;\n    }\n\n    if (randomTiming) {\n      capability.randomTiming = true;\n    }\n\n    return capability;\n  },\n\n  getRotationCapType: ({ channelName, channelType }) => {\n    if (['Pan', 'Tilt'].includes(channelType)) {\n      return `${channelType}Continuous`;\n    }\n\n    if (['Colour', 'Gobo'].includes(channelType) || /gobo/i.test(channelName)) {\n      return /wheel/i.test(channelName) ? 'WheelRotation' : 'WheelSlotRotation';\n    }\n\n    if (channelType === 'Prism') {\n      return 'PrismRotation';\n    }\n\n    return 'Rotation';\n  },\n\n  getRotationSpeedCap: (capabilityData, speedStart = '', speedEnd = '') => {\n    const capability = {\n      type: importHelpers.getRotationCapType(capabilityData),\n    };\n\n    if (capability.type.startsWith('Wheel') && !capabilityData.channelNameInWheels) {\n      capability.wheel = '';\n    }\n\n    if (speedEnd) {\n      capability.speedStart = speedStart;\n      capability.speedEnd = speedEnd;\n    }\n    else if (speedStart) {\n      capability.speed = speedStart;\n    }\n\n    return capability;\n  },\n\n  getSpeedCapType: ({ channelName, channelType }) => {\n    if (channelType === 'Shutter' || /strobe/i.test(channelName)) {\n      return 'StrobeSpeed';\n    }\n\n    if (/pan\\W*tilt/i.test(channelName)) {\n      return 'PanTiltSpeed';\n    }\n\n    if (channelType === 'Effect' || /program|effect/i.test(channelName)) {\n      return 'EffectSpeed';\n    }\n\n    return 'Speed';\n  },\n\n  getBeamAngleCap({ channelName, channelType }, isAscending) {\n    if (channelType === 'Shutter' || /iris/i.test(channelName)) {\n      const [openPercentStart, openPercentEnd] = isAscending ? ['closed', 'open'] : ['open', 'closed'];\n\n      return {\n        type: 'Iris',\n        openPercentStart,\n        openPercentEnd,\n      };\n    }\n\n    const [angleStart, angleEnd] = isAscending ? ['small', 'big'] : ['big', 'small'];\n\n    return {\n      type: /zoom/i.test(channelName) ? 'Zoom' : 'BeamAngle',\n      angleStart,\n      angleEnd,\n    };\n  },\n\n  /**\n   * @param {string | undefined} direction A string containing something like \"CW\", \"CCW\", \"clockwise\", \"counter-clockwise\".\n   * @returns {string} The normalized direction suffix.\n   */\n  getDirectionSuffix(direction) {\n    if (!direction) {\n      return '';\n    }\n\n    return /counter|ccw/i.test(direction) ? ' CCW' : ' CW';\n  },\n\n  /**\n   * Try to guess speedStart / speedEnd from the capability name and set them\n   * to the capability. It may also set cap.type to \"Rotation\".\n   * @param {string} capabilityName The capability name to extract information from.\n   * @param {object} capability The OFL capability object to add found properties to.\n   * @returns {string} The rest of the capabilityName.\n   */\n  getSpeedGuessedComment(capabilityName, capability) {\n    const speedRegex = /(?:^|,\\s*|\\s+)\\(?((?:(?:counter\\s?-?\\s?)?clockwise|c?cw).*?(?:,\\s*|\\s+))?\\(?(slow|fast|\\d+|\\d+\\s*hz)\\s*(?:-|to|–|…|\\.{2,}|->|<->|→)\\s*(fast|slow|\\d+\\s*hz)\\)?$/i;\n    if (speedRegex.test(capabilityName)) {\n      return capabilityName.replace(speedRegex, (_, direction, start, end) => {\n        const directionSuffix = importHelpers.getDirectionSuffix(direction);\n        if (directionSuffix !== '') {\n          capability.type = 'Rotation';\n        }\n\n        start = start.toLowerCase();\n        end = end.toLowerCase();\n\n        const startNumber = Number.parseFloat(start);\n        const endNumber = Number.parseFloat(end);\n        if (!Number.isNaN(startNumber) && !Number.isNaN(endNumber)) {\n          start = `${startNumber}Hz`;\n          end = `${endNumber}Hz`;\n        }\n\n        capability.speedStart = start + directionSuffix;\n        capability.speedEnd = end + directionSuffix;\n\n        // delete the parsed part\n        return '';\n      });\n    }\n\n    const stopRegex = /\\s*\\b(?:stop(?:ped)?|no rotation|no rotate)\\b\\s*/gi;\n    if (stopRegex.test(capabilityName)) {\n      return capabilityName.replaceAll(stopRegex, () => {\n        capability.speed = 'stop';\n        return '';\n      });\n    }\n\n    return capabilityName;\n  },\n\n  getMaintenanceCap: (capabilityData) => ({\n    type: 'Maintenance',\n    comment: capabilityData.capabilityName,\n  }),\n};\n\nconst createWheelRotationCapability = () => ({\n  type: 'WheelRotation',\n  wheel: '',\n  speedStart: 'slow',\n  speedEnd: 'fast',\n});\n\nconst createFocusNearToFarCapability = () => ({\n  type: 'Focus',\n  distanceStart: 'near',\n  distanceEnd: 'far',\n});\n\nconst createFocusFarToNearCapability = () => ({\n  type: 'Focus',\n  distanceStart: 'far',\n  distanceEnd: 'near',\n});\n\n// ########## Channel presets ##########\n\nconst channelPresets = {\n  IntensityMasterDimmer: {\n    isApplicable: (capability) => {\n      const channel = capability._channel;\n      const matrix = channel.fixture.matrix;\n\n      if (!channelPresets.IntensityDimmer.isApplicable(capability) || matrix === null) {\n        return false;\n      }\n\n      return channel.pixelKey === null || matrix.pixelGroups[channel.pixelKey] === matrix.pixelKeys;\n    },\n    importCapability: () => ({ type: 'Intensity' }),\n  },\n  IntensityDimmer: {\n    isApplicable: (capability) => capability.type === 'Intensity' && capability.brightness[0].number < capability.brightness[1].number,\n    importCapability: () => ({ type: 'Intensity' }),\n  },\n\n  IntensityRed: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Red'),\n    importCapability: () => importHelpers.getColorIntensityCap('Red'),\n  },\n  IntensityGreen: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Green'),\n    importCapability: () => importHelpers.getColorIntensityCap('Green'),\n  },\n  IntensityBlue: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Blue'),\n    importCapability: () => importHelpers.getColorIntensityCap('Blue'),\n  },\n  IntensityCyan: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Cyan'),\n    importCapability: () => importHelpers.getColorIntensityCap('Cyan'),\n  },\n  IntensityMagenta: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Magenta'),\n    importCapability: () => importHelpers.getColorIntensityCap('Magenta'),\n  },\n  IntensityYellow: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Yellow'),\n    importCapability: () => importHelpers.getColorIntensityCap('Yellow'),\n  },\n  IntensityAmber: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Amber'),\n    importCapability: () => importHelpers.getColorIntensityCap('Amber'),\n  },\n  IntensityWhite: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'White') || exportHelpers.isColorIntensity(capability, 'Warm White') || exportHelpers.isColorIntensity(capability, 'Cold White'),\n    importCapability: ({ channelName }) => {\n      let color = 'White';\n      if (/\\bwarm\\b/i.test(channelName)) {\n        color = 'Warm White';\n      }\n      else if (/\\bcold\\b/i.test(channelName)) {\n        color = 'Cold White';\n      }\n\n      return {\n        type: 'ColorIntensity',\n        color,\n      };\n    },\n  },\n  IntensityUV: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'UV'),\n    importCapability: () => importHelpers.getColorIntensityCap('UV'),\n  },\n  IntensityIndigo: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Indigo'),\n    importCapability: () => importHelpers.getColorIntensityCap('Indigo'),\n  },\n  IntensityLime: {\n    isApplicable: (capability) => exportHelpers.isColorIntensity(capability, 'Lime'),\n    importCapability: () => importHelpers.getColorIntensityCap('Lime'),\n  },\n\n  IntensityHue: {\n    isApplicable: (capability) => false,\n    importCapability: () => ({ type: 'Generic' }),\n  },\n  IntensitySaturation: {\n    isApplicable: (capability) => false,\n    importCapability: () => ({ type: 'Generic' }),\n  },\n  IntensityLightness: {\n    isApplicable: (capability) => false,\n    importCapability: () => ({ type: 'Generic' }),\n  },\n  IntensityValue: {\n    isApplicable: (capability) => false,\n    importCapability: () => ({ type: 'Generic' }),\n  },\n\n  PositionPan: {\n    isApplicable: (capability) => capability.type === 'Pan',\n    importCapability: ({ panMax }) => importHelpers.getPanTiltCap('Pan', panMax),\n  },\n  PositionTilt: {\n    isApplicable: (capability) => capability.type === 'Tilt',\n    importCapability: ({ tiltMax }) => importHelpers.getPanTiltCap('Tilt', tiltMax),\n  },\n  PositionXAxis: {\n    isApplicable: (capability) => capability.type === 'BeamPosition' && capability.horizontalAngle && capability.horizontalAngle[0].number < capability.horizontalAngle[1].number,\n    importCapability: () => ({\n      type: 'BeamPosition',\n      horizontalAngleStart: 'left',\n      horizontalAngleEnd: 'right',\n      helpWanted: 'Is this the correct direction? Can you provide exact angles?',\n    }),\n  },\n  PositionYAxis: {\n    isApplicable: (capability) => capability.type === 'BeamPosition' && capability.verticalAngle && capability.verticalAngle[0].number < capability.verticalAngle[1].number,\n    importCapability: () => ({\n      type: 'BeamPosition',\n      verticalAngleStart: 'top',\n      verticalAngleEnd: 'bottom',\n      helpWanted: 'Is this the correct direction? Can you provide exact angles?',\n    }),\n  },\n  SpeedPanSlowFast: {\n    isApplicable: (capability) => capability.type === 'PanContinuous' && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => ({\n      type: 'PanContinuous',\n      speedStart: 'slow',\n      speedEnd: 'fast',\n    }),\n  },\n  SpeedPanFastSlow: {\n    isApplicable: (capability) => capability.type === 'PanContinuous' && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => ({\n      type: 'PanContinuous',\n      speedStart: 'fast',\n      speedEnd: 'slow',\n    }),\n  },\n  SpeedTiltSlowFast: {\n    isApplicable: (capability) => capability.type === 'TiltContinuous' && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => ({\n      type: 'TiltContinuous',\n      speedStart: 'slow',\n      speedEnd: 'fast',\n    }),\n  },\n  SpeedTiltFastSlow: {\n    isApplicable: (capability) => capability.type === 'TiltContinuous' && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => ({\n      type: 'TiltContinuous',\n      speedStart: 'fast',\n      speedEnd: 'slow',\n    }),\n  },\n  SpeedPanTiltSlowFast: {\n    isApplicable: (capability) => capability.type === 'PanTiltSpeed' && (exportHelpers.isIncreasingSpeed(capability) || exportHelpers.isDecreasingDuration(capability)),\n    importCapability: () => ({\n      type: 'PanTiltSpeed',\n      speedStart: 'slow',\n      speedEnd: 'fast',\n    }),\n  },\n  SpeedPanTiltFastSlow: {\n    isApplicable: (capability) => capability.type === 'PanTiltSpeed' && (exportHelpers.isDecreasingSpeed(capability) || exportHelpers.isIncreasingDuration(capability)),\n    importCapability: () => ({\n      type: 'PanTiltSpeed',\n      speedStart: 'fast',\n      speedEnd: 'slow',\n    }),\n  },\n\n  ColorMacro: {\n    isApplicable: (capability) => capability.type === 'ColorPreset' || (capability.type === 'WheelSlot' && capability.isSlotType('Color')),\n    importCapability: () => ({\n      type: 'ColorPreset',\n      helpWanted: 'Which color can be selected at which DMX values?',\n    }),\n  },\n  ColorWheel: {\n    isApplicable: (capability) => capability.type === 'WheelRotation' && capability.wheels[0].type === 'Color',\n    importCapability: createWheelRotationCapability,\n  },\n  ColorRGBMixer: {\n    isApplicable: (capability) => channelPresets.IntensityHue.isApplicable(capability),\n    importCapability: (capabilityData) => channelPresets.IntensityHue.importCapability(capabilityData),\n  },\n  ColorCTOMixer: {\n    isApplicable: (capability) => capability.type === 'ColorTemperature' && capability.colorTemperature[0].number === 0 && capability.colorTemperature[1].number < 0,\n    importCapability: () => ({\n      type: 'ColorTemperature',\n      colorTemperatureStart: 'default',\n      colorTemperatureEnd: 'warm',\n      helpWanted: 'Can you provide exact color temperature values in Kelvin?',\n    }),\n  },\n  ColorCTBMixer: {\n    isApplicable: (capability) => capability.type === 'ColorTemperature' && capability.colorTemperature[0].number === 0 && capability.colorTemperature[1].number > 0,\n    importCapability: () => ({\n      type: 'ColorTemperature',\n      colorTemperatureStart: 'default',\n      colorTemperatureEnd: 'cold',\n      helpWanted: 'Can you provide exact color temperature values in Kelvin?',\n    }),\n  },\n  ColorCTCMixer: {\n    isApplicable: (capability) => capability.type === 'ColorTemperature',\n    importCapability: () => ({\n      type: 'ColorTemperature',\n      colorTemperatureStart: 'warm',\n      colorTemperatureEnd: 'cold',\n      helpWanted: 'Is this the correct direction? Can you provide exact color temperature values in Kelvin?',\n    }),\n  },\n\n  GoboWheel: {\n    isApplicable: (capability) => capability.type === 'WheelRotation' && capability.wheels[0].type === 'Gobo',\n    importCapability: createWheelRotationCapability,\n  },\n  GoboIndex: {\n    isApplicable: (capability) => capability.type === 'WheelSlotRotation' && capability.wheels[0].type === 'Gobo',\n    importCapability: () => ({\n      type: 'WheelSlotRotation',\n      angleStart: '0deg',\n      angleEnd: '360deg',\n      helpWanted: 'Are these the correct angles?',\n    }),\n  },\n\n  ShutterStrobeSlowFast: {\n    isApplicable: (capability) => capability.type === 'ShutterStrobe' && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => ({\n      type: 'ShutterStrobe',\n      shutterEffect: 'Strobe',\n      speedStart: 'slow',\n      speedEnd: 'fast',\n      helpWanted: 'At which DMX values is strobe disabled? When is the lamp constantly on/off?',\n    }),\n  },\n  ShutterStrobeFastSlow: {\n    isApplicable: (capability) => capability.type === 'ShutterStrobe' && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => ({\n      type: 'ShutterStrobe',\n      shutterEffect: 'Strobe',\n      speedStart: 'fast',\n      speedEnd: 'slow',\n      helpWanted: 'At which DMX values is strobe disabled? When is the lamp constantly on/off?',\n    }),\n  },\n  ShutterIrisMinToMax: {\n    isApplicable: (capability) => capability.type === 'Iris' && capability.openPercent[0].number < capability.openPercent[1].number,\n    importCapability: () => ({\n      type: 'Iris',\n      openPercentStart: 'closed',\n      openPercentEnd: 'open',\n    }),\n  },\n  ShutterIrisMaxToMin: {\n    isApplicable: (capability) => capability.type === 'Iris' && capability.openPercent[0].number > capability.openPercent[1].number,\n    importCapability: () => ({\n      type: 'Iris',\n      openPercentStart: 'open',\n      openPercentEnd: 'closed',\n    }),\n  },\n\n  BeamFocusNearFar: {\n    isApplicable: (capability) => capability.type === 'Focus' && capability.distance[0].number < capability.distance[1].number,\n    importCapability: createFocusNearToFarCapability,\n  },\n  BeamFocusFarNear: {\n    isApplicable: (capability) => capability.type === 'Focus' && capability.distance[0].number > capability.distance[1].number,\n    importCapability: createFocusFarToNearCapability,\n  },\n  BeamZoomSmallBig: {\n    isApplicable: (capability) => capability.type === 'Zoom' && capability.angle[0].number < capability.angle[1].number,\n    importCapability: () => ({\n      type: 'Zoom',\n      angleStart: 'narrow',\n      angleEnd: 'wide',\n    }),\n  },\n  BeamZoomBigSmall: {\n    isApplicable: (capability) => capability.type === 'Zoom' && capability.angle[0].number > capability.angle[1].number,\n    importCapability: () => ({\n      type: 'Zoom',\n      angleStart: 'wide',\n      angleEnd: 'narrow',\n    }),\n  },\n  PrismRotationSlowFast: {\n    isApplicable: (capability) => capability.type === 'PrismRotation' && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => ({\n      type: 'PrismRotation',\n      speedStart: 'slow CW',\n      speedEnd: 'fast CW',\n      helpWanted: 'Does the prism rotate clockwise or counter-clockwise?',\n    }),\n  },\n  PrismRotationFastSlow: {\n    isApplicable: (capability) => capability.type === 'PrismRotation' && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => ({\n      type: 'PrismRotation',\n      speedStart: 'fast CW',\n      speedEnd: 'slow CW',\n      helpWanted: 'Does the prism rotate clockwise or counter-clockwise?',\n    }),\n  },\n\n  NoFunction: {\n    isApplicable: (capability) => capability.type === 'NoFunction',\n    importCapability: () => ({ type: 'NoFunction' }),\n  },\n};\n\n/**\n * @param {CoarseChannel} channel The OFL channel object.\n * @returns {string | null} The QLC+ channel preset name or null, if there is no suitable one.\n */\nexport function getChannelPreset(channel) {\n  if (channel.capabilities.length > 1) {\n    return null;\n  }\n\n  return Object.keys(channelPresets).find(\n    (preset) => channelPresets[preset].isApplicable(channel.capabilities[0]),\n  ) || null;\n}\n\n/**\n * @param {string} preset The channel preset to import.\n * @param {string} channelName The channel name.\n * @param {number} panMax The maximum pan angle, or 0.\n * @param {number} tiltMax The maximum tilt angle, or 0.\n * @returns {object} The OFL capability object.\n */\nexport function getCapabilityFromChannelPreset(preset, channelName, panMax, tiltMax) {\n  if (preset in channelPresets) {\n    return channelPresets[preset].importCapability({\n      channelName,\n      panMax,\n      tiltMax,\n    });\n  }\n\n  return {\n    type: 'Generic',\n    helpWanted: `Unknown QLC+ channel preset ${preset}.`,\n  };\n}\n\n// ########## Fine channel presets ##########\n\nconst fineChannelPresets = {\n  IntensityMasterDimmerFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityMasterDimmer',\n  },\n  IntensityDimmerFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityDimmer',\n  },\n\n  IntensityRedFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityRed',\n  },\n  IntensityGreenFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityGreen',\n  },\n  IntensityBlueFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityBlue',\n  },\n  IntensityCyanFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityCyan',\n  },\n  IntensityMagentaFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityMagenta',\n  },\n  IntensityYellowFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityYellow',\n  },\n  IntensityAmberFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityAmber',\n  },\n  IntensityWhiteFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityWhite',\n  },\n  IntensityUVFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityUV',\n  },\n  IntensityIndigoFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityIndigo',\n  },\n  IntensityLimeFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityLime',\n  },\n\n  IntensityHueFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityHue',\n  },\n  IntensitySaturationFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensitySaturation',\n  },\n  IntensityLightnessFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityLightness',\n  },\n  IntensityValueFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'IntensityValue',\n  },\n\n  PositionPanFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'PositionPan',\n  },\n  PositionTiltFine: {\n    isApplicable: ({ coarseChannelPreset }) => coarseChannelPreset === 'PositionTilt',\n  },\n\n  ColorWheelFine: {\n    isApplicable: ({ coarseChannel }) => exportHelpers.isWheelChannel(coarseChannel) && coarseChannel.capabilities.every(\n      (capability) => exportHelpers.isAllowedInWheels(capability) && (capability.wheels.length === 0 || capability.wheels[0].type === 'Color'),\n    ),\n  },\n  GoboWheelFine: {\n    isApplicable: ({ coarseChannel }) => exportHelpers.isWheelChannel(coarseChannel) && coarseChannel.capabilities.every(\n      (capability) => exportHelpers.isAllowedInWheels(capability) && (capability.wheels.length === 0 || capability.wheels[0].type === 'Gobo'),\n    ),\n  },\n  GoboIndexFine: {\n    isApplicable: ({ coarseChannel }) => coarseChannel.capabilities.every(\n      (capability) => capability.type === 'WheelSlotRotation' && capability.wheels[0].type === 'Gobo',\n    ),\n  },\n\n  ShutterIrisFine: {\n    isApplicable: ({ coarseChannel }) => coarseChannel.type === 'Iris',\n  },\n  BeamFocusFine: {\n    isApplicable: ({ coarseChannel }) => coarseChannel.type === 'Focus',\n  },\n  BeamZoomFine: {\n    isApplicable: ({ coarseChannel }) => coarseChannel.type === 'Zoom',\n  },\n};\n\n/**\n * @param {FineChannel} fineChannel The OFL fine channel object.\n * @returns {string | null} The QLC+ channel preset name or null, if there is no suitable one.\n */\nexport function getFineChannelPreset(fineChannel) {\n  const coarseChannel = fineChannel.coarseChannel;\n  const coarseChannelPreset = getChannelPreset(coarseChannel);\n\n  return Object.keys(fineChannelPresets).find(\n    (fineChannelPreset) => fineChannelPresets[fineChannelPreset].isApplicable({\n      coarseChannel,\n      coarseChannelPreset,\n    }),\n  ) || null;\n}\n\n// ########## Capability presets ##########\n\nexport const capabilityPresets = {\n\n  // shutter capabilities\n\n  ShutterOpen: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Open'),\n    importCapability: () => ({\n      type: 'ShutterStrobe',\n      shutterEffect: 'Open',\n    }),\n  },\n  ShutterClose: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Closed'),\n    importCapability: () => ({\n      type: 'ShutterStrobe',\n      shutterEffect: 'Closed',\n    }),\n  },\n\n  // strobe capabilities with specified frequency\n\n  StrobeFrequency: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Strobe') && exportHelpers.hasFrequency(capability) && capability.isStep,\n    exportRes1: (capability) => capability.speed[0].baseUnitEntity.number,\n    importCapability: ({ res1 }) => importHelpers.getShutterStrobeCap('Strobe', `${res1}Hz`),\n  },\n  StrobeFreqRange: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Strobe') && exportHelpers.hasFrequency(capability),\n    exportRes1: (capability) => capability.speed[0].baseUnitEntity.number,\n    exportRes2: (capability) => capability.speed[1].baseUnitEntity.number,\n    importCapability: ({ res1, res2 }) => importHelpers.getShutterStrobeCap('Strobe', `${res1}Hz`, `${res2}Hz`),\n  },\n  PulseFrequency: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Pulse') && exportHelpers.hasFrequency(capability) && capability.isStep,\n    exportRes1: (capability) => capability.speed[0].baseUnitEntity.number,\n    importCapability: ({ res1 }) => importHelpers.getShutterStrobeCap('Pulse', `${res1}Hz`),\n  },\n  PulseFreqRange: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Pulse') && exportHelpers.hasFrequency(capability),\n    exportRes1: (capability) => capability.speed[0].baseUnitEntity.number,\n    exportRes2: (capability) => capability.speed[1].baseUnitEntity.number,\n    importCapability: ({ res1, res2 }) => importHelpers.getShutterStrobeCap('Pulse', `${res1}Hz`, `${res2}Hz`),\n  },\n  RampUpFrequency: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'RampUp') && exportHelpers.hasFrequency(capability) && capability.isStep,\n    exportRes1: (capability) => capability.speed[0].baseUnitEntity.number,\n    importCapability: ({ res1 }) => importHelpers.getShutterStrobeCap('RampUp', `${res1}Hz`),\n  },\n  RampUpFreqRange: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'RampUp') && exportHelpers.hasFrequency(capability),\n    exportRes1: (capability) => capability.speed[0].baseUnitEntity.number,\n    exportRes2: (capability) => capability.speed[1].baseUnitEntity.number,\n    importCapability: ({ res1, res2 }) => importHelpers.getShutterStrobeCap('RampUp', `${res1}Hz`, `${res2}Hz`),\n  },\n  RampDownFrequency: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'RampDown') && exportHelpers.hasFrequency(capability) && capability.isStep,\n    exportRes1: (capability) => capability.speed[0].baseUnitEntity.number,\n    importCapability: ({ res1 }) => importHelpers.getShutterStrobeCap('RampDown', `${res1}Hz`),\n  },\n  RampDownFreqRange: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'RampDown') && exportHelpers.hasFrequency(capability),\n    exportRes1: (capability) => capability.speed[0].baseUnitEntity.number,\n    exportRes2: (capability) => capability.speed[1].baseUnitEntity.number,\n    importCapability: ({ res1, res2 }) => importHelpers.getShutterStrobeCap('RampDown', `${res1}Hz`, `${res2}Hz`),\n  },\n\n  // other strobe capabilities\n\n  StrobeRandomSlowToFast: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Strobe') && capability.randomTiming && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('Strobe', 'slow', 'fast', true),\n  },\n  StrobeRandomFastToSlow: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Strobe') && capability.randomTiming && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('Strobe', 'fast', 'slow', true),\n  },\n  StrobeRandom: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Strobe') && capability.randomTiming,\n    importCapability: () => importHelpers.getShutterStrobeCap('Strobe', null, null, true),\n  },\n  StrobeSlowToFast: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Strobe') && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('Strobe', 'slow', 'fast'),\n  },\n  StrobeFastToSlow: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Strobe') && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('Strobe', 'fast', 'slow'),\n  },\n  PulseSlowToFast: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Pulse') && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('Pulse', 'slow', 'fast'),\n  },\n  PulseFastToSlow: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'Pulse') && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('Pulse', 'fast', 'slow'),\n  },\n  RampUpSlowToFast: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'RampUp') && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('RampUp', 'slow', 'fast'),\n  },\n  RampUpFastToSlow: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'RampUp') && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('RampUp', 'fast', 'slow'),\n  },\n  RampDownSlowToFast: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'RampDown') && exportHelpers.isIncreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('RampDown', 'slow', 'fast'),\n  },\n  RampDownFastToSlow: {\n    isApplicable: (capability) => exportHelpers.isShutterEffect(capability, 'RampDown') && exportHelpers.isDecreasingSpeed(capability),\n    importCapability: () => importHelpers.getShutterStrobeCap('RampDown', 'fast', 'slow'),\n  },\n\n  // color capabilities\n\n  ColorMacro: {\n    isApplicable: (capability) => (capability.type === 'ColorPreset' || capability.isSlotType('Color')) && capability.colors !== null && capability.colors.allColors.length === 1,\n    exportRes1: (capability) => capability.colors.allColors[0],\n    importCapability: (capabilityData) => capabilityPresets.ColorDoubleMacro.importCapability(capabilityData),\n  },\n  ColorDoubleMacro: {\n    isApplicable: (capability) => (capability.type === 'ColorPreset' || capability.isSlotType('Color')) && capability.colors !== null && capability.colors.allColors.length === 2,\n    exportRes1: (capability) => capability.colors.allColors[0],\n    exportRes2: (capability) => capability.colors.allColors[1],\n    importCapability: ({ channelName, res1, res2, index }) => {\n      if (/wheel\\b/i.test(channelName)) {\n        return {\n          type: 'WheelSlot',\n          slotNumber: index + 1,\n        };\n      }\n\n      const colors = [res1];\n      if (res2) {\n        colors.push(res2);\n      }\n\n      return {\n        type: 'ColorPreset',\n        comment: '',\n        colors,\n      };\n    },\n  },\n  ColorWheelIndex: {\n    isApplicable: (capability) => capability.type === 'WheelRotation' && capability.wheels[0].type === 'Color' && exportHelpers.isRotationAngle(capability),\n    importCapability: () => ({\n      type: 'WheelRotation',\n      angleStart: '0deg',\n      angleEnd: '360deg',\n      helpWanted: 'Are these the correct angles?',\n    }),\n  },\n\n  // gobo capabilities\n\n  // TODO: import/export a gobo image as res1\n  GoboShakeMacro: {\n    isApplicable: (capability) => capability.type === 'WheelShake' && capability.isSlotType(/Gobo|Iris|Frost|Open/),\n    exportRes1: exportHelpers.getGoboResource,\n    importCapability: ({ capabilityName, index }) => {\n      const capability = {\n        type: 'WheelShake',\n        slotNumber: index + 1,\n      };\n\n      const comment = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n      if ('speed' in capability) {\n        capability.shakeSpeed = capability.speed;\n        delete capability.speed;\n      }\n      else if ('speedStart' in capability) {\n        capability.shakeSpeedStart = capability.speedStart;\n        capability.shakeSpeedEnd = capability.speedEnd;\n        delete capability.speedStart;\n        delete capability.speedEnd;\n      }\n\n      capability.comment = comment;\n\n      return capability;\n    },\n  },\n  GoboMacro: {\n    isApplicable: (capability) => capability.type === 'WheelSlot' && capability.isSlotType(/Gobo|Iris|Frost|Open/),\n    exportRes1: exportHelpers.getGoboResource,\n    importCapability: ({ index }) => ({\n      type: 'WheelSlot',\n      slotNumber: index + 1,\n    }),\n  },\n\n  // prism capabilities\n\n  PrismEffectOn: {\n    isApplicable: (capability) => capability.type === 'Prism' || (capability.type === 'WheelSlot' && capability.isSlotType('Prism')),\n    exportRes1: (capability) => (capability.wheelSlot && capability.slotNumber[0].number === capability.slotNumber[1].number && capability.wheelSlot[0].facets),\n    importCapability: (capabilityData) => {\n      if (/wheel/i.test(capabilityData.channelName)) {\n        return capabilityPresets.GoboMacro.importCapability(capabilityData);\n      }\n\n      return {\n        type: 'Prism',\n        comment: capabilityData.res1 ? `${capabilityData.res1}-facet` : '',\n      };\n    },\n  },\n  PrismEffectOff: {\n    isApplicable: (capability) => capability.type === 'NoFunction' && capability._channel.type === 'Prism',\n    importCapability: () => ({\n      type: 'NoFunction',\n    }),\n  },\n\n  // rotation capabilities\n\n  RotationClockwiseSlowToFast: {\n    isApplicable: (capability) => exportHelpers.isRotationSpeed(capability) && exportHelpers.isIncreasingSpeed(capability) && capability.speed[0].number > 0,\n    importCapability: (capabilityData) => importHelpers.getRotationSpeedCap(capabilityData, 'slow CW', 'fast CW'),\n  },\n  RotationClockwiseFastToSlow: {\n    isApplicable: (capability) => exportHelpers.isRotationSpeed(capability) && exportHelpers.isDecreasingSpeed(capability) && capability.speed[1].number > 0,\n    importCapability: (capabilityData) => importHelpers.getRotationSpeedCap(capabilityData, 'fast CW', 'slow CW'),\n  },\n  RotationClockwise: {\n    isApplicable: (capability) => exportHelpers.isRotationSpeed(capability) && capability.speed[0].number === capability.speed[1].number && capability.speed[0].number > 0,\n    importCapability: (capabilityData) => importHelpers.getRotationSpeedCap(capabilityData, 'fast CW'),\n  },\n  RotationStop: {\n    isApplicable: (capability) => exportHelpers.isRotationSpeed(capability) && exportHelpers.isStopped(capability),\n    importCapability: (capabilityData) => importHelpers.getRotationSpeedCap(capabilityData, 'stop'),\n  },\n  RotationCounterClockwiseSlowToFast: {\n    isApplicable: (capability) => exportHelpers.isRotationSpeed(capability) && exportHelpers.isIncreasingSpeed(capability) && capability.speed[0].number < 0,\n    importCapability: (capabilityData) => importHelpers.getRotationSpeedCap(capabilityData, 'slow CCW', 'fast CCW'),\n  },\n  RotationCounterClockwiseFastToSlow: {\n    isApplicable: (capability) => exportHelpers.isRotationSpeed(capability) && exportHelpers.isDecreasingSpeed(capability) && capability.speed[1].number < 0,\n    importCapability: (capabilityData) => importHelpers.getRotationSpeedCap(capabilityData, 'fast CCW', 'slow CCW'),\n  },\n  RotationCounterClockwise: {\n    isApplicable: (capability) => exportHelpers.isRotationSpeed(capability) && capability.speed[0].number === capability.speed[1].number && capability.speed[0].number < 0,\n    importCapability: (capabilityData) => importHelpers.getRotationSpeedCap(capabilityData, 'fast CCW'),\n  },\n  RotationIndexed: {\n    isApplicable: (capability) => exportHelpers.isRotationAngle(capability),\n    importCapability: (capabilityData) => ({\n      type: importHelpers.getRotationCapType(capabilityData),\n      angleStart: '0deg',\n      angleEnd: '360deg',\n      helpWanted: 'Are these the correct angles?',\n    }),\n  },\n\n  // maintenance / reset capabilities\n\n  ResetPanTilt: {\n    isApplicable: (capability) =>\n      capability.type === 'Maintenance'\n      && /\\breset\\b/i.test(capability.comment)\n      && (\n        (/\\bpan\\b/i.test(capability.comment) && /\\btilt\\b/i.test(capability.comment))\n        || /\\bposition\\b|\\bscan\\b/i.test(capability.comment)\n      ),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetPan: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bpan\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetTilt: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\btilt\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetEffects: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\beffects?\\b|\\bbeam\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetGobo: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bgobos?\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetColor: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bcolou?rs?\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetCMY: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bcmy\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetCTO: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bcto\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetPrism: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bprisms?\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetBlades: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bblades?\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetIris: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\biris\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetFrost: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bfrost\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetZoom: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment) && /\\bzoom\\b|\\bfocus\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetMotors: {\n    isApplicable: (capability) =>\n      capability.type === 'Maintenance'\n      && /\\breset\\b/i.test(capability.comment)\n      && /\\bmotors?\\b/i.test(capability.comment)\n      && !/\\ball\\b|\\btotal\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  ResetAll: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\breset\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  LampOn: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\blamp\\b/i.test(capability.comment) && /\\bon\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  LampOff: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\blamp\\b/i.test(capability.comment) && /\\boff\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  SilentModeOn: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\bsilent\\b/i.test(capability.comment) && /\\bon\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  SilentModeOff: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\bsilent\\b/i.test(capability.comment) && /\\boff\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n  SilentModeAutomatic: {\n    isApplicable: (capability) => capability.type === 'Maintenance' && /\\bsilent\\b/i.test(capability.comment) && /\\bauto(?:matic)?\\b/i.test(capability.comment),\n    importCapability: importHelpers.getMaintenanceCap,\n  },\n\n  // generic / other capabilities\n\n  GenericPicture: {\n    isApplicable: (capability) => capability.effectPreset === 'ColorFade' && !exportHelpers.isStopped(capability),\n    exportRes1: (capability) => 'Others/rainbow.png',\n    importCapability: ({ res1, channelName, capabilityName }) => {\n      if (res1 === 'Others/rainbow.png') {\n        if (/wheel/i.test(channelName)) {\n          const capability = {\n            type: 'WheelRotation',\n          };\n          capability.comment = importHelpers.getSpeedGuessedComment(capabilityName, capability);\n\n          if (!('speed' in capability || 'speedStart' in capability)) {\n            capability.speedStart = 'slow CW';\n            capability.speedEnd = 'fast CW';\n            capability.helpWanted = 'Are the automatically added speed values correct?';\n          }\n\n          return capability;\n        }\n        return {\n          type: 'Effect',\n          effectName: capabilityName,\n        };\n      }\n\n      return {\n        type: 'Generic',\n        comment: res1,\n      };\n    },\n  },\n  SlowToFast: {\n    isApplicable: (capability) => exportHelpers.isIncreasingSpeed(capability),\n    importCapability: (capabilityData) => ({\n      type: importHelpers.getSpeedCapType(capabilityData),\n      speedStart: 'slow',\n      speedEnd: 'fast',\n    }),\n  },\n  FastToSlow: {\n    isApplicable: (capability) => exportHelpers.isDecreasingSpeed(capability),\n    importCapability: (capabilityData) => ({\n      type: importHelpers.getSpeedCapType(capabilityData),\n      speedStart: 'fast',\n      speedEnd: 'slow',\n    }),\n  },\n  NearToFar: {\n    isApplicable: (capability) => capability.distance !== null && capability.distance[0].number < capability.distance[1].number,\n    importCapability: createFocusNearToFarCapability,\n  },\n  FarToNear: {\n    isApplicable: (capability) => capability.distance !== null && capability.distance[0].number > capability.distance[1].number,\n    importCapability: createFocusFarToNearCapability,\n  },\n  SmallToBig: {\n    isApplicable: (capability) => (exportHelpers.isBeamAngle(capability) && capability.angle[0].number < capability.angle[1].number) || (capability.parameter !== null && capability.parameter[0].keyword === 'small' && capability.parameter[1].keyword === 'big'),\n    importCapability: (capabilityData) => importHelpers.getBeamAngleCap(capabilityData, true),\n  },\n  BigToSmall: {\n    isApplicable: (capability) => (exportHelpers.isBeamAngle(capability) && capability.angle[0].number > capability.angle[1].number) || (capability.parameter !== null && capability.parameter[0].keyword === 'big' && capability.parameter[1].keyword === 'small'),\n    importCapability: (capabilityData) => importHelpers.getBeamAngleCap(capabilityData, false),\n  },\n};\n\n/**\n * @typedef {object} CapabilityPreset\n * @property {string} presetName The name of the QLC+ capability preset.\n * @property {string | null} res1 A value for the QLC+ capability element's Res1 attribute, or null if the attribute should not be added.\n * @property {string | null} res2 A value for the QLC+ capability element's Res2 attribute, or null if the attribute should not be added.\n */\n\n/**\n * @param {Capability} capability The OFL capability object.\n * @returns {Promise<CapabilityPreset | null>} A Promise that resolves to the QLC+ capability preset or null, if there is no suitable one.\n */\nexport async function getCapabilityPreset(capability) {\n  const foundPresetName = Object.keys(capabilityPresets).find(\n    (presetName) => capabilityPresets[presetName].isApplicable(capability),\n  );\n\n  if (!foundPresetName) {\n    return null;\n  }\n\n  const preset = capabilityPresets[foundPresetName];\n  return {\n    presetName: foundPresetName,\n    res1: 'exportRes1' in preset ? await preset.exportRes1(capability) : null,\n    res2: 'exportRes2' in preset ? preset.exportRes2(capability) : null,\n  };\n}\n\n/**\n * @param {string} preset The capability preset to import.\n * @param {object} capabilityData Additional data about capability and channel.\n * @returns {object} The OFL capability object.\n */\nexport function getCapabilityFromCapabilityPreset(preset, capabilityData) {\n  if (preset in capabilityPresets) {\n    const capability = capabilityPresets[preset].importCapability(capabilityData);\n\n    if (!capability.comment || capabilityData.capabilityName.includes(capability.comment)) {\n      capability.comment = capabilityData.capabilityName;\n    }\n    else {\n      capability.comment += ` ${capabilityData.capabilityName}`;\n    }\n\n    return capability;\n  }\n\n  return {\n    type: 'Generic',\n    comment: capabilityData.capabilityName,\n    helpWanted: `Unknown QLC+ capability preset ${preset}, Res1=\"${capabilityData.res1}\", Res2=\"${capabilityData.res2}\".`,\n  };\n}\n"
  },
  {
    "path": "resources/gobos/1-vertical-bar.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"1 vertical bars\",\n  \"keywords\": \"lines\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/10-circles.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"10 circles\",\n  \"keywords\": \"dots\",\n  \"source\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/resources/gobos/glass-red-10-circles.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/3-fold-spiral.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"3-fold spiral\",\n  \"keywords\": \"three-fold\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/Chauvet/gobo00037.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/3-fold-swirl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Swirl\",\n  \"keywords\": \"twist\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00038.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/32-circles.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"32 circles\",\n  \"keywords\": \"dots\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/4-line-arranged-dots.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"2 lines with 4 dots each\",\n  \"keywords\": \"lines circles\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/4-vertical-bars.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"4 vertical bars\",\n  \"keywords\": \"lines\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/ClayPaky/gobo00104.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/5-fold-swirl-inverted.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"5-fold swirl (inverted)\",\n  \"keywords\": \"spiral five-fold\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/5-fold-swirl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"5-fold swirl\",\n  \"keywords\": \"spiral five-fold\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/Others/gobo00046.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/5-pointed-compass-rose-star.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"5-pointed compass-rose star\",\n  \"keywords\": \"five-pointed\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/SGM/gobo00123.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/5-pointed-star.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"5-Pointed Star\",\n  \"keywords\": \"five-pointed pentagram\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00042.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/6-mouse-heads.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"6 mouse heads\",\n  \"keywords\": \"mice animals\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/Chauvet/gobo00102.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/aliases/qlcplus.json",
    "content": "{\n  \"Chauvet/gobo00017.svg\": \"rose-petal\",\n  \"Chauvet/gobo00034.svg\": \"bubbles\",\n  \"Chauvet/gobo00035.svg\": \"daisy-flower\",\n  \"Chauvet/gobo00037.svg\": \"3-fold-spiral\",\n  \"Chauvet/gobo00045.svg\": \"circular-drops\",\n  \"Chauvet/gobo00046.png\": \"circular-droplets\",\n  \"Chauvet/gobo00048.svg\": \"striped-iris\",\n  \"Chauvet/gobo00049.svg\": \"circular-beams\",\n  \"Chauvet/gobo00050.png\": \"stars\",\n  \"Chauvet/gobo00052.svg\": \"hypnotic-swirl\",\n  \"Chauvet/gobo00053.svg\": \"fragmented-star\",\n  \"Chauvet/gobo00101.svg\": \"clockwork\",\n  \"Chauvet/gobo00102.svg\": \"6-mouse-heads\",\n\n  \"ClayPaky/gobo00097.svg\": \"vibrating-triangle\",\n  \"ClayPaky/gobo00104.svg\": \"4-vertical-bars\",\n\n  \"Others/gobo00001.svg\": \"glass-red-10-circles\",\n  \"Others/gobo00025.svg\": \"square-arrows\",\n  \"Others/gobo00028.svg\": \"stones\",\n  \"Others/gobo00030.svg\": \"square-outline\",\n  \"Others/gobo00038.svg\": \"3-fold-swirl\",\n  \"Others/gobo00039.svg\": \"biohazard\",\n  \"Others/gobo00040.svg\": \"triangle-hexagon-pattern\",\n  \"Others/gobo00041.svg\": \"dot-spiral\",\n  \"Others/gobo00042.svg\": \"5-pointed-star\",\n  \"Others/gobo00046.svg\": \"5-fold-swirl\",\n  \"Others/gobo00091.svg\": \"double-lines-star\",\n  \"Others/gobo00113.png\": \"glass-raindrops-on-window\",\n\n  \"SGM/gobo00123.svg\": \"5-pointed-compass-rose-star\",\n  \"SGM/gobo00136.svg\": \"crescent\",\n  \"SGM/gobo00361.svg\": \"caro-flower\",\n  \"SGM/gobo00362.svg\": \"circled-clock-face\"\n}\n"
  },
  {
    "path": "resources/gobos/biohazard.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Biohazard\",\n  \"keywords\": \"warning virus viral\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00039.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/bubbles.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Bubbles\",\n  \"keywords\": \"circles\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/Chauvet/gobo00034.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/caro-flower.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Caro Flower\",\n  \"keywords\": \"flower floral petals\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/SGM/gobo00361.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/circle-outline.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Circle Outline\",\n  \"keywords\": \"frame\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/circled-clock-face.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Circled clock face\",\n  \"keywords\": \"time\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/SGM/gobo00362.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/circular-beams.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Circular Beams\",\n  \"keywords\": \"beam\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Chauvet/gobo00049.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/circular-droplets.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Circular droplets\",\n  \"keywords\": \"rain droplet\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Chauvet/gobo00046.png\"\n}\n"
  },
  {
    "path": "resources/gobos/circular-drops.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Circular Drops\",\n  \"keywords\": \"drop raindrop\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Chauvet/gobo00045.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/clockwork.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Clockwork\",\n  \"keywords\": \"gears cogs\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/Chauvet/gobo00101.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/comets.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"comets\",\n  \"keywords\": \"circles dots\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/crescent.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Crescent\",\n  \"keywords\": \"elliptic eclipse\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/SGM/gobo00136.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/daisy-flower.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Daisy flower\",\n  \"keywords\": \"petals\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/Chauvet/gobo00035.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/dot-spiral.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Dot spiral\",\n  \"keywords\": \"milkyway galaxy stars\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00041.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/double-lines-star.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Double Lines Star\",\n  \"keywords\": \"star lines rays\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00091.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/edge-touching-circles.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Edge-touching Circles\",\n  \"keywords\": \"beam\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/fragmented-star.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Fragmented Star\",\n  \"keywords\": \"star fragment\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Chauvet/gobo00053.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/glass-raindrops-on-window.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Raindrops on window\",\n  \"keywords\": \"glass waves water\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00113.png\"\n}\n"
  },
  {
    "path": "resources/gobos/glass-red-10-circles.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Red with 10 circles\",\n  \"keywords\": \"glass dots\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00001.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/hypnotic-swirl.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Hypnotic Swirl\",\n  \"keywords\": \"swirl hypnotic\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Chauvet/gobo00052.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/pointed-grid.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"pointed grid\",\n  \"keywords\": \"grid\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/quarter-mark.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"quarter mark\",\n  \"keywords\": \"grid\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/rays.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"rays\",\n  \"keywords\": \"lines\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/rose-petal-abstract.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Rose petal abstract\",\n  \"keywords\": \"flower\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/rose-petal.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Rose petal\",\n  \"keywords\": \"flower\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Chauvet/gobo00017.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/shards.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"shards\",\n  \"keywords\": \"shards\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/square-arrows.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Square Arrows\",\n  \"keywords\": \"arrows square directional\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00025.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/square-outline.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Square outline\",\n  \"keywords\": \"frame\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/Others/gobo00030.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/stars.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Stars\",\n  \"keywords\": \"star\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Chauvet/gobo00050.png\"\n}\n"
  },
  {
    "path": "resources/gobos/stones.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Stones\",\n  \"keywords\": \"pebbles rocks texture\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00028.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/striped-iris.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Striped Iris\",\n  \"keywords\": \"iris stripe\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Chauvet/gobo00048.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/tiny-stars.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"tiny stars\",\n  \"keywords\": \"stars\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/triangle-hexagon-pattern.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Triangle/hexagon pattern\",\n  \"keywords\": \"honeycomb\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/QLC+_4.12.2/resources/gobos/Others/gobo00040.svg\"\n}\n"
  },
  {
    "path": "resources/gobos/triangle-outline.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Triangle Outline\",\n  \"keywords\": \"frame\",\n  \"source\": \"https://fast-images.static-thomann.de/pics/atg/atgdata/document/manual/c_477539_v3_en_online.pdf\"\n}\n"
  },
  {
    "path": "resources/gobos/vibrating-triangle.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n  \"name\": \"Vibrating triangle\",\n  \"keywords\": \"triangular\",\n  \"source\": \"https://github.com/mcallegari/qlcplus/blob/master/resources/gobos/ClayPaky/gobo00097.svg\"\n}\n"
  },
  {
    "path": "schemas/capability.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/capability.json\",\n\n  \"$comment\": \"This file is used by another schema file and should not be used directly as a JSON schema.\",\n\n  \"definitions\": {\n    \"dmxRange\": {\n      \"type\": \"array\",\n      \"minItems\": 2,\n      \"maxItems\": 2,\n      \"items\": { \"$ref\": \"definitions.json#/units/dmxValue\" }\n    },\n    \"menuClick\": {\n      \"enum\": [\"start\", \"center\", \"end\", \"hidden\"]\n    },\n    \"switchChannels\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"propertyNames\": {\n        \"$comment\": \"switching channel alias keys\",\n        \"oneOf\": [\n          { \"$ref\": \"definitions.json#/noVariablesString\" },\n          { \"$ref\": \"definitions.json#/variablePixelKeyString\" }\n        ]\n      },\n      \"additionalProperties\": {\n        \"oneOf\": [\n          {\n            \"$comment\": \"channel key or channel alias key\",\n            \"$ref\": \"definitions.json#/noVariablesString\"\n          },\n          {\n            \"$comment\": \"template channel key or template channel alias key\",\n            \"$ref\": \"definitions.json#/variablePixelKeyString\"\n          }\n        ]\n      }\n    }\n  },\n\n  \"type\": \"object\",\n  \"discriminator\": { \"propertyName\": \"type\" },\n  \"oneOf\": [\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"NoFunction\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"ShutterStrobe\" },\n        \"shutterEffect\": { \"enum\": [\n          \"Open\",\n          \"Closed\",\n          \"Strobe\",\n          \"Pulse\",\n          \"RampUp\",\n          \"RampDown\",\n          \"RampUpDown\",\n          \"Lightning\",\n          \"Spikes\",\n          \"Burst\"\n        ] },\n        \"soundControlled\": { \"type\": \"boolean\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"duration\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationStart\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationEnd\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"randomTiming\": { \"type\": \"boolean\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\", \"shutterEffect\"],\n      \"not\": {\n        \"anyOf\": [\n          { \"required\": [\"speed\", \"speedStart\"] },\n          { \"required\": [\"duration\", \"durationStart\"] }\n        ]\n      },\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"],\n        \"durationStart\": [\"durationEnd\"],\n        \"durationEnd\": [\"durationStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"StrobeSpeed\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"StrobeDuration\" },\n        \"duration\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationStart\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationEnd\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"duration\"] },\n        { \"required\": [\"durationStart\"] }\n      ],\n      \"dependencies\": {\n        \"durationStart\": [\"durationEnd\"],\n        \"durationEnd\": [\"durationStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Intensity\" },\n        \"brightness\": { \"$ref\": \"definitions.json#/entities/brightness\" },\n        \"brightnessStart\": { \"$ref\": \"definitions.json#/entities/brightness\" },\n        \"brightnessEnd\": { \"$ref\": \"definitions.json#/entities/brightness\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"not\": { \"required\": [\"brightness\", \"brightnessStart\"] },\n      \"dependencies\": {\n        \"brightnessStart\": [\"brightnessEnd\"],\n        \"brightnessEnd\": [\"brightnessStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"ColorIntensity\" },\n        \"color\": {\n          \"enum\": [\n            \"Red\",\n            \"Green\",\n            \"Blue\",\n            \"Cyan\",\n            \"Magenta\",\n            \"Yellow\",\n            \"Amber\",\n            \"White\",\n            \"Warm White\",\n            \"Cold White\",\n            \"UV\",\n            \"Lime\",\n            \"Indigo\"\n          ]\n        },\n        \"brightness\": { \"$ref\": \"definitions.json#/entities/brightness\" },\n        \"brightnessStart\": { \"$ref\": \"definitions.json#/entities/brightness\" },\n        \"brightnessEnd\": { \"$ref\": \"definitions.json#/entities/brightness\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\", \"color\"],\n      \"not\": { \"required\": [\"brightness\", \"brightnessStart\"] },\n      \"dependencies\": {\n        \"brightnessStart\": [\"brightnessEnd\"],\n        \"brightnessEnd\": [\"brightnessStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"ColorPreset\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"colors\": {\n          \"type\": \"array\",\n          \"minItems\": 1,\n          \"items\": { \"$ref\": \"definitions.json#/colorString\" }\n        },\n        \"colorsStart\": {\n          \"type\": \"array\",\n          \"minItems\": 1,\n          \"items\": { \"$ref\": \"definitions.json#/colorString\" }\n        },\n        \"colorsEnd\": {\n          \"type\": \"array\",\n          \"minItems\": 1,\n          \"items\": { \"$ref\": \"definitions.json#/colorString\" }\n        },\n        \"colorTemperature\": { \"$ref\": \"definitions.json#/entities/colorTemperature\" },\n        \"colorTemperatureStart\": { \"$ref\": \"definitions.json#/entities/colorTemperature\" },\n        \"colorTemperatureEnd\": { \"$ref\": \"definitions.json#/entities/colorTemperature\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"not\": {\n        \"anyOf\": [\n          { \"required\": [\"colors\", \"colorsStart\"] },\n          { \"required\": [\"colorTemperature\", \"colorTemperatureStart\"] }\n        ]\n      },\n      \"dependencies\": {\n        \"colorsStart\": [\"colorsEnd\"],\n        \"colorsEnd\": [\"colorsStart\"],\n        \"colorTemperatureStart\": [\"colorTemperatureEnd\"],\n        \"colorTemperatureEnd\": [\"colorTemperatureStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"ColorTemperature\" },\n        \"colorTemperature\": { \"$ref\": \"definitions.json#/entities/colorTemperature\" },\n        \"colorTemperatureStart\": { \"$ref\": \"definitions.json#/entities/colorTemperature\" },\n        \"colorTemperatureEnd\": { \"$ref\": \"definitions.json#/entities/colorTemperature\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"colorTemperature\"] },\n        { \"required\": [\"colorTemperatureStart\"] }\n      ],\n      \"dependencies\": {\n        \"colorTemperatureStart\": [\"colorTemperatureEnd\"],\n        \"colorTemperatureEnd\": [\"colorTemperatureStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Pan\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"PanContinuous\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Tilt\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"TiltContinuous\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"PanTiltSpeed\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"duration\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationStart\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationEnd\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] },\n        { \"required\": [\"duration\"] },\n        { \"required\": [\"durationStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"],\n        \"durationStart\": [\"durationEnd\"],\n        \"durationEnd\": [\"durationStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"WheelSlot\" },\n        \"wheel\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"slotNumber\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"slotNumberStart\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"slotNumberEnd\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"slotNumber\"] },\n        { \"required\": [\"slotNumberStart\"] }\n      ],\n      \"dependencies\": {\n        \"slotNumberStart\": [\"slotNumberEnd\"],\n        \"slotNumberEnd\": [\"slotNumberStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"WheelShake\" },\n        \"wheel\": {},\n        \"isShaking\": {\n          \"enum\": [\"wheel\", \"slot\"]\n        },\n        \"slotNumber\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"slotNumberStart\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"slotNumberEnd\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"shakeSpeed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"shakeSpeedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"shakeSpeedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"shakeAngle\": { \"$ref\": \"definitions.json#/entities/swingAngle\" },\n        \"shakeAngleStart\": { \"$ref\": \"definitions.json#/entities/swingAngle\" },\n        \"shakeAngleEnd\": { \"$ref\": \"definitions.json#/entities/swingAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"not\": {\n        \"anyOf\": [\n          { \"required\": [\"slotNumber\", \"slotNumberStart\"] },\n          { \"required\": [\"shakeSpeed\", \"shakeSpeedStart\"] },\n          { \"required\": [\"shakeAngle\", \"shakeAngleStart\"] }\n        ]\n      },\n      \"dependencies\": {\n        \"shakeSpeedStart\": [\"shakeSpeedEnd\"],\n        \"shakeSpeedEnd\": [\"shakeSpeedStart\"],\n        \"shakeAngleStart\": [\"shakeAngleEnd\"],\n        \"shakeAngleEnd\": [\"shakeAngleStart\"],\n        \"slotNumberStart\": [\"slotNumberEnd\"],\n        \"slotNumberEnd\": [\"slotNumberStart\"]\n      },\n      \"if\": {\n        \"$comment\": \"slotNumber is set\",\n        \"anyOf\": [\n          { \"required\": [\"slotNumber\"] },\n          { \"required\": [\"slotNumberStart\"] }\n        ]\n      },\n      \"then\": {\n        \"$comment\": \"wheel must be a single wheel\",\n        \"properties\": {\n          \"wheel\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n        }\n      },\n      \"else\": {\n        \"$comment\": \"wheel can be a single wheel or multiple wheels\",\n        \"properties\": {\n          \"wheel\": {\n            \"oneOf\": [\n              { \"$ref\": \"definitions.json#/nonEmptyString\" },\n              {\n                \"type\": \"array\",\n                \"uniqueItems\": true,\n                \"minItems\": 2,\n                \"items\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n              }\n            ]\n          }\n        }\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"WheelSlotRotation\" },\n        \"wheel\": {},\n        \"slotNumber\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"slotNumberStart\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"slotNumberEnd\": { \"$ref\": \"definitions.json#/entities/slotNumber\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] },\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"not\": { \"required\": [\"slotNumber\", \"slotNumberStart\"] },\n      \"dependencies\": {\n        \"slotNumberStart\": [\"slotNumberEnd\"],\n        \"slotNumberEnd\": [\"slotNumberStart\"],\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"],\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"if\": {\n        \"$comment\": \"slotNumber is set\",\n        \"anyOf\": [\n          { \"required\": [\"slotNumber\"] },\n          { \"required\": [\"slotNumberStart\"] }\n        ]\n      },\n      \"then\": {\n        \"$comment\": \"wheel must be a single wheel\",\n        \"properties\": {\n          \"wheel\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n        }\n      },\n      \"else\": {\n        \"$comment\": \"wheel can be a single wheel or multiple wheels\",\n        \"properties\": {\n          \"wheel\": {\n            \"oneOf\": [\n              { \"$ref\": \"definitions.json#/nonEmptyString\" },\n              {\n                \"type\": \"array\",\n                \"uniqueItems\": true,\n                \"minItems\": 2,\n                \"items\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n              }\n            ]\n          }\n        }\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"WheelRotation\" },\n        \"wheel\": {\n          \"oneOf\": [\n            { \"$ref\": \"definitions.json#/nonEmptyString\" },\n            {\n              \"type\": \"array\",\n              \"uniqueItems\": true,\n              \"minItems\": 2,\n              \"items\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n            }\n          ]\n        },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] },\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"],\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Effect\" },\n        \"effectName\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"effectPreset\": { \"$ref\": \"definitions.json#/effectPreset\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"duration\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationStart\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationEnd\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"parameter\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"parameterStart\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"parameterEnd\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"soundControlled\": { \"type\": \"boolean\" },\n        \"soundSensitivity\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"soundSensitivityStart\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"soundSensitivityEnd\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"effectName\"] },\n        { \"required\": [\"effectPreset\"] }\n      ],\n      \"not\": {\n        \"anyOf\": [\n          { \"required\": [\"speed\", \"speedStart\"] },\n          { \"required\": [\"duration\", \"durationStart\"] },\n          { \"required\": [\"parameter\", \"parameterStart\"] },\n          { \"required\": [\"soundSensitivity\", \"soundSensitivityStart\"] }\n        ]\n      },\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"],\n        \"durationStart\": [\"durationEnd\"],\n        \"durationEnd\": [\"durationStart\"],\n        \"parameterStart\": [\"parameterEnd\"],\n        \"parameterEnd\": [\"parameterStart\"],\n        \"soundSensitivityStart\": [\"soundSensitivityEnd\"],\n        \"soundSensitivityEnd\": [\"soundSensitivityStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"EffectSpeed\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"EffectDuration\" },\n        \"duration\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationStart\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"durationEnd\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"duration\"] },\n        { \"required\": [\"durationStart\"] }\n      ],\n      \"dependencies\": {\n        \"durationStart\": [\"durationEnd\"],\n        \"durationEnd\": [\"durationStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"EffectParameter\" },\n        \"parameter\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"parameterStart\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"parameterEnd\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"parameter\"] },\n        { \"required\": [\"parameterStart\"] }\n      ],\n      \"dependencies\": {\n        \"parameterStart\": [\"parameterEnd\"],\n        \"parameterEnd\": [\"parameterStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"SoundSensitivity\" },\n        \"soundSensitivity\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"soundSensitivityStart\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"soundSensitivityEnd\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"soundSensitivity\"] },\n        { \"required\": [\"soundSensitivityStart\"] }\n      ],\n      \"dependencies\": {\n        \"soundSensitivityStart\": [\"soundSensitivityEnd\"],\n        \"soundSensitivityEnd\": [\"soundSensitivityStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"BeamAngle\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/beamAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/beamAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/beamAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"BeamPosition\" },\n        \"horizontalAngle\": { \"$ref\": \"definitions.json#/entities/horizontalAngle\" },\n        \"horizontalAngleStart\": { \"$ref\": \"definitions.json#/entities/horizontalAngle\" },\n        \"horizontalAngleEnd\": { \"$ref\": \"definitions.json#/entities/horizontalAngle\" },\n        \"verticalAngle\": { \"$ref\": \"definitions.json#/entities/verticalAngle\" },\n        \"verticalAngleStart\": { \"$ref\": \"definitions.json#/entities/verticalAngle\" },\n        \"verticalAngleEnd\": { \"$ref\": \"definitions.json#/entities/verticalAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"anyOf\": [\n        { \"oneOf\": [\n          { \"required\": [\"horizontalAngle\"] },\n          { \"required\": [\"horizontalAngleStart\"] }\n        ] },\n        { \"oneOf\": [\n          { \"required\": [\"verticalAngle\"] },\n          { \"required\": [\"verticalAngleStart\"] }\n        ] }\n      ],\n      \"dependencies\": {\n        \"horizontalAngleStart\": [\"horizontalAngleEnd\"],\n        \"horizontalAngleEnd\": [\"horizontalAngleStart\"],\n        \"verticalAngleStart\": [\"verticalAngleEnd\"],\n        \"verticalAngleEnd\": [\"verticalAngleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Focus\" },\n        \"distance\": { \"$ref\": \"definitions.json#/entities/distance\" },\n        \"distanceStart\": { \"$ref\": \"definitions.json#/entities/distance\" },\n        \"distanceEnd\": { \"$ref\": \"definitions.json#/entities/distance\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"distance\"] },\n        { \"required\": [\"distanceStart\"] }\n      ],\n      \"dependencies\": {\n        \"distanceStart\": [\"distanceEnd\"],\n        \"distanceEnd\": [\"distanceStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Zoom\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/beamAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/beamAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/beamAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Iris\" },\n        \"openPercent\": { \"$ref\": \"definitions.json#/entities/irisPercent\" },\n        \"openPercentStart\": { \"$ref\": \"definitions.json#/entities/irisPercent\" },\n        \"openPercentEnd\": { \"$ref\": \"definitions.json#/entities/irisPercent\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"openPercent\"] },\n        { \"required\": [\"openPercentStart\"] }\n      ],\n      \"dependencies\": {\n        \"openPercentStart\": [\"openPercentEnd\"],\n        \"openPercentEnd\": [\"openPercentStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"IrisEffect\" },\n        \"effectName\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\", \"effectName\"],\n      \"not\": { \"required\": [\"speed\", \"speedStart\"] },\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Frost\" },\n        \"frostIntensity\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"frostIntensityStart\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"frostIntensityEnd\": { \"$ref\": \"definitions.json#/entities/percent\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"frostIntensity\"] },\n        { \"required\": [\"frostIntensityStart\"] }\n      ],\n      \"dependencies\": {\n        \"frostIntensityStart\": [\"frostIntensityEnd\"],\n        \"frostIntensityEnd\": [\"frostIntensityStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"FrostEffect\" },\n        \"effectName\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\", \"effectName\"],\n      \"not\": { \"required\": [\"speed\", \"speedStart\"] },\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Prism\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"not\": {\n        \"anyOf\": [\n          { \"required\": [\"speed\", \"speedStart\"] },\n          { \"required\": [\"angle\", \"angleStart\"] },\n          { \"required\": [\"speed\", \"angle\"] },\n          { \"required\": [\"speed\", \"angleStart\"] },\n          { \"required\": [\"speedStart\", \"angle\"] },\n          { \"required\": [\"speedStart\", \"angleStart\"] }\n        ]\n      },\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"],\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"PrismRotation\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] },\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"],\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"BladeInsertion\" },\n        \"blade\": {\n          \"oneOf\": [\n            { \"enum\": [\"Top\", \"Right\", \"Bottom\", \"Left\"] },\n            { \"$ref\": \"definitions.json#/units/positiveInteger\" }\n          ]\n        },\n        \"insertion\": { \"$ref\": \"definitions.json#/entities/insertion\" },\n        \"insertionStart\": { \"$ref\": \"definitions.json#/entities/insertion\" },\n        \"insertionEnd\": { \"$ref\": \"definitions.json#/entities/insertion\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\", \"blade\"],\n      \"oneOf\": [\n        { \"required\": [\"insertion\"] },\n        { \"required\": [\"insertionStart\"] }\n      ],\n      \"dependencies\": {\n        \"insertionStart\": [\"insertionEnd\"],\n        \"insertionEnd\": [\"insertionStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"BladeRotation\" },\n        \"blade\": {\n          \"oneOf\": [\n            { \"enum\": [\"Top\", \"Right\", \"Bottom\", \"Left\"] },\n            { \"$ref\": \"definitions.json#/units/positiveInteger\" }\n          ]\n        },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\", \"blade\"],\n      \"oneOf\": [\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"BladeSystemRotation\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Fog\" },\n        \"fogType\": { \"enum\": [\"Fog\", \"Haze\"] },\n        \"fogOutput\": { \"$ref\": \"definitions.json#/entities/fogOutput\" },\n        \"fogOutputStart\": { \"$ref\": \"definitions.json#/entities/fogOutput\" },\n        \"fogOutputEnd\": { \"$ref\": \"definitions.json#/entities/fogOutput\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"not\": { \"required\": [\"fogOutput\", \"fogOutputStart\"] },\n      \"dependencies\": {\n        \"fogOutputStart\": [\"fogOutputEnd\"],\n        \"fogOutputEnd\": [\"fogOutputStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"FogOutput\" },\n        \"fogOutput\": { \"$ref\": \"definitions.json#/entities/fogOutput\" },\n        \"fogOutputStart\": { \"$ref\": \"definitions.json#/entities/fogOutput\" },\n        \"fogOutputEnd\": { \"$ref\": \"definitions.json#/entities/fogOutput\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"fogOutput\"] },\n        { \"required\": [\"fogOutputStart\"] }\n      ],\n      \"dependencies\": {\n        \"fogOutputStart\": [\"fogOutputEnd\"],\n        \"fogOutputEnd\": [\"fogOutputStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"FogType\" },\n        \"fogType\": { \"enum\": [\"Fog\", \"Haze\"] },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\", \"fogType\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Rotation\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/rotationSpeed\" },\n        \"angle\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleStart\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"angleEnd\": { \"$ref\": \"definitions.json#/entities/rotationAngle\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] },\n        { \"required\": [\"angle\"] },\n        { \"required\": [\"angleStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"],\n        \"angleStart\": [\"angleEnd\"],\n        \"angleEnd\": [\"angleStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Speed\" },\n        \"speed\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedStart\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"speedEnd\": { \"$ref\": \"definitions.json#/entities/speed\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"speed\"] },\n        { \"required\": [\"speedStart\"] }\n      ],\n      \"dependencies\": {\n        \"speedStart\": [\"speedEnd\"],\n        \"speedEnd\": [\"speedStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Time\" },\n        \"time\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"timeStart\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"timeEnd\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"oneOf\": [\n        { \"required\": [\"time\"] },\n        { \"required\": [\"timeStart\"] }\n      ],\n      \"dependencies\": {\n        \"timeStart\": [\"timeEnd\"],\n        \"timeEnd\": [\"timeStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Maintenance\" },\n        \"parameter\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"parameterStart\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"parameterEnd\": { \"$ref\": \"definitions.json#/entities/parameter\" },\n        \"hold\": { \"$ref\": \"definitions.json#/entities/time\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"not\": { \"required\": [\"parameter\", \"parameterStart\"] },\n      \"dependencies\": {\n        \"parameterStart\": [\"parameterEnd\"],\n        \"parameterEnd\": [\"parameterStart\"]\n      },\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"dmxRange\": { \"$ref\": \"#/definitions/dmxRange\" },\n        \"type\": { \"const\": \"Generic\" },\n        \"comment\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"menuClick\": { \"$ref\": \"#/definitions/menuClick\" },\n        \"switchChannels\": { \"$ref\": \"#/definitions/switchChannels\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    }\n  ]\n}\n"
  },
  {
    "path": "schemas/channel.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/channel.json\",\n\n  \"$comment\": \"This file is used by another schema file and should not be used directly as a JSON schema.\",\n\n  \"type\": \"object\",\n  \"properties\": {\n    \"name\": {\n      \"description\": \"if not set: use channel key\",\n      \"$ref\": \"definitions.json#/nonEmptyString\"\n    },\n    \"fineChannelAliases\": {\n      \"type\": \"array\",\n      \"minItems\": 1,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"oneOf\": [\n          { \"$ref\": \"definitions.json#/noVariablesString\" },\n          {\n            \"$ref\": \"definitions.json#/variablePixelKeyString\",\n            \"$comment\": \"only in template channels\"\n          }\n        ]\n      }\n    },\n    \"dmxValueResolution\": { \"enum\": [\"8bit\", \"16bit\", \"24bit\"] },\n    \"defaultValue\": { \"oneOf\": [\n      { \"$ref\": \"definitions.json#/units/dmxValue\" },\n      { \"$ref\": \"definitions.json#/units/dmxValuePercent\" }\n    ] },\n    \"highlightValue\": { \"oneOf\": [\n      { \"$ref\": \"definitions.json#/units/dmxValue\" },\n      { \"$ref\": \"definitions.json#/units/dmxValuePercent\" }\n    ] },\n    \"constant\": { \"type\": \"boolean\" },\n    \"precedence\": { \"enum\": [\"LTP\", \"HTP\"] },\n    \"capability\": {\n      \"allOf\": [{ \"$ref\": \"capability.json#\" }],\n      \"not\": {\n        \"anyOf\": [\n          { \"required\": [\"dmxRange\"] },\n          { \"required\": [\"switchChannels\"] }\n        ]\n      }\n    },\n    \"capabilities\": {\n      \"type\": \"array\",\n      \"minItems\": 2,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"allOf\": [{ \"$ref\": \"capability.json#\" }],\n        \"required\": [\"dmxRange\"]\n      }\n    }\n  },\n  \"dependencies\": {\n    \"dmxValueResolution\": [\"fineChannelAliases\"]\n  },\n  \"oneOf\": [\n    { \"required\": [\"capability\"] },\n    { \"required\": [\"capabilities\"] }\n  ],\n  \"allOf\": [\n    {\n      \"if\": {\n        \"$comment\": \"one capability sets switchChannels\",\n        \"properties\": {\n          \"capabilities\": {\n            \"contains\": {\n              \"required\": [\"switchChannels\"]\n            }\n          }\n        },\n        \"required\": [\"capabilities\"]\n      },\n      \"then\": {\n        \"$comment\": \"defaultValue must be set and all capabilities have to set switchChannels\",\n        \"required\": [\"defaultValue\"],\n        \"properties\": {\n          \"capabilities\": {\n            \"items\": {\n              \"required\": [\"switchChannels\"]\n            }\n          }\n        }\n      }\n    },\n    {\n      \"if\": {\n        \"$comment\": \"channel contains only one NoFunction capability\",\n        \"properties\": {\n          \"capability\": {\n            \"properties\": {\n              \"type\": { \"const\": \"NoFunction\" }\n            }\n          }\n        },\n        \"required\": [\"capability\"]\n      },\n      \"then\": {\n        \"$comment\": \"fineChannelAliases must not be set\",\n        \"not\": {\n          \"required\": [\"fineChannelAliases\"]\n        }\n      }\n    }\n  ],\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "schemas/definitions.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/definitions.json\",\n\n  \"$comment\": \"This file is used by another schema file and should not be used directly as a JSON schema.\",\n\n  \"nonEmptyString\": {\n    \"type\": \"string\",\n    \"pattern\": \"^[^\\n]+$\"\n  },\n  \"noVariablesString\": {\n    \"type\": \"string\",\n    \"pattern\": \"^[^$\\n]+$\"\n  },\n  \"variablePixelKeyString\": {\n    \"type\": \"string\",\n    \"pattern\": \"\\\\$pixelKey\"\n  },\n  \"nonEmptyMultilineString\": {\n    \"type\": \"string\",\n    \"minLength\": 1\n  },\n  \"modeNameString\": {\n    \"allOf\": [\n      { \"$ref\": \"#/nonEmptyString\" },\n      { \"pattern\": \"^((?!mode)(?!Mode).)*$\" }\n    ]\n  },\n  \"urlString\": {\n    \"type\": \"string\",\n    \"pattern\": \"^(ftp|http|https)://[^ \\\"]+$\",\n    \"format\": \"uri\"\n  },\n  \"urlArray\": {\n    \"type\": \"array\",\n    \"minItems\": 1,\n    \"uniqueItems\": true,\n    \"items\": { \"$ref\": \"#/urlString\" }\n  },\n  \"isoDateString\": {\n    \"type\": \"string\",\n    \"pattern\": \"^[0-9]{4}-[0-9]{2}-[0-9]{2}$\",\n    \"format\": \"date\"\n  },\n  \"colorString\": {\n    \"type\": \"string\",\n    \"pattern\": \"^#[0-9a-f]{6}$\",\n    \"format\": \"color-hex\"\n  },\n  \"dimensionsXYZ\": {\n    \"description\": \"width, height, depth (in mm)\",\n    \"type\": \"array\",\n    \"minItems\": 3,\n    \"maxItems\": 3,\n    \"items\": {\n      \"type\": \"number\",\n      \"minimum\": 0\n    }\n  },\n  \"effectPreset\": {\n    \"enum\": [\n      \"ColorJump\",\n      \"ColorFade\"\n    ]\n  },\n  \"goboResourceString\": {\n    \"type\": \"string\",\n    \"pattern\": \"^gobos/[a-z0-9-]+$|^gobos/aliases/[a-z0-9_.-]+/\"\n  },\n  \"powerConnectorType\": {\n    \"enum\": [\n      \"input only\",\n      \"output only\",\n      \"input and output\"\n    ]\n  },\n\n  \"units\": {\n    \"number\": {\n      \"type\": \"number\"\n    },\n    \"nonNegativeNumber\": {\n      \"type\": \"number\",\n      \"minimum\": 0\n    },\n    \"positiveInteger\": {\n      \"type\": \"integer\",\n      \"minimum\": 0,\n      \"exclusiveMinimum\": 0\n    },\n    \"dmxValue\": {\n      \"type\": \"integer\",\n      \"minimum\": 0,\n      \"$comment\": \"maximum depends on how many fine channels there are (255 if none, 65535 if one, etc.)\"\n    },\n    \"dmxValuePercent\": {\n      \"type\": \"string\",\n      \"pattern\": \"^(([1-9][0-9]?|0)(\\\\.[0-9]+)?|100)%$\"\n    },\n    \"percent\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?%$\"\n    },\n    \"hertz\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?Hz$\"\n    },\n    \"beatsPerMinute\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?bpm$\"\n    },\n    \"roundsPerMinute\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?rpm$\"\n    },\n    \"seconds\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?s$\"\n    },\n    \"milliSeconds\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?ms$\"\n    },\n    \"meters\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?m$\"\n    },\n    \"lumens\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?lm$\"\n    },\n    \"kelvin\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?K$\"\n    },\n    \"volumePerMinute\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?m\\\\^3/min$\"\n    },\n    \"degrees\": {\n      \"type\": \"string\",\n      \"pattern\": \"^-?[0-9]+(\\\\.[0-9]+)?deg$\"\n    }\n  },\n\n  \"entities\": {\n    \"speed\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/hertz\" },\n        { \"$ref\": \"#/units/beatsPerMinute\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"fast\", \"slow\", \"stop\", \"slow reverse\", \"fast reverse\"] }\n      ]\n    },\n    \"rotationSpeed\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/hertz\" },\n        { \"$ref\": \"#/units/roundsPerMinute\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"fast CW\", \"slow CW\", \"stop\", \"slow CCW\", \"fast CCW\"] }\n      ]\n    },\n    \"time\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/seconds\" },\n        { \"$ref\": \"#/units/milliSeconds\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"instant\", \"short\", \"long\"] }\n      ]\n    },\n    \"distance\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/meters\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"near\", \"far\"] }\n      ]\n    },\n    \"brightness\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/lumens\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"off\", \"dark\", \"bright\"] }\n      ]\n    },\n    \"colorTemperature\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/kelvin\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"warm\", \"CTO\", \"default\", \"cold\", \"CTB\"] }\n      ]\n    },\n    \"fogOutput\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/volumePerMinute\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"off\", \"weak\", \"strong\"] }\n      ]\n    },\n    \"rotationAngle\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/degrees\" },\n        { \"$ref\": \"#/units/percent\" }\n      ]\n    },\n    \"beamAngle\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/degrees\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"closed\", \"narrow\", \"wide\"] }\n      ]\n    },\n    \"horizontalAngle\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/degrees\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"left\", \"center\", \"right\"] }\n      ]\n    },\n    \"verticalAngle\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/degrees\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"top\", \"center\", \"bottom\"] }\n      ]\n    },\n    \"swingAngle\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/degrees\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"closed\", \"narrow\", \"wide\"] }\n      ]\n    },\n    \"parameter\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/number\" },\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"off\", \"low\", \"high\", \"slow\", \"fast\", \"small\", \"big\", \"instant\", \"short\", \"long\"] }\n      ]\n    },\n    \"slotNumber\": {\n      \"$ref\": \"#/units/nonNegativeNumber\"\n    },\n    \"percent\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"off\", \"low\", \"high\"] }\n      ]\n    },\n    \"insertion\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"out\", \"in\"] }\n      ]\n    },\n    \"irisPercent\": {\n      \"oneOf\": [\n        { \"$ref\": \"#/units/percent\" },\n        { \"enum\": [\"closed\", \"open\"] }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "schemas/fixture-redirect.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\",\n\n  \"version\": \"12.5.0\",\n\n  \"type\": \"object\",\n  \"properties\": {\n    \"$schema\": {\n      \"const\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture-redirect.json\"\n    },\n    \"name\": {\n      \"description\": \"unique in manufacturer\",\n      \"$ref\": \"definitions.json#/nonEmptyString\"\n    },\n    \"redirectTo\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[a-z0-9\\\\-]+/[a-z0-9\\\\-]+$\"\n    },\n    \"reason\": {\n      \"enum\": [\n        \"FixtureRenamed\",\n        \"SameAsDifferentBrand\"\n      ]\n    }\n  },\n  \"required\": [\"$schema\", \"name\", \"redirectTo\", \"reason\"],\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "schemas/fixture.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\",\n\n  \"version\": \"12.5.0\",\n\n  \"type\": \"object\",\n  \"properties\": {\n    \"$schema\": {\n      \"const\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json\"\n    },\n    \"name\": {\n      \"description\": \"unique in manufacturer\",\n      \"$ref\": \"definitions.json#/nonEmptyString\"\n    },\n    \"shortName\": {\n      \"description\": \"unique globally; if not set: use name\",\n      \"$ref\": \"definitions.json#/nonEmptyString\"\n    },\n    \"categories\": {\n      \"type\": \"array\",\n      \"description\": \"most important category first\",\n      \"minItems\": 1,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"enum\": [\n          \"Barrel Scanner\",\n          \"Blinder\",\n          \"Color Changer\",\n          \"Dimmer\",\n          \"Effect\",\n          \"Fan\",\n          \"Flower\",\n          \"Hazer\",\n          \"Laser\",\n          \"Matrix\",\n          \"Moving Head\",\n          \"Pixel Bar\",\n          \"Scanner\",\n          \"Smoke\",\n          \"Stand\",\n          \"Strobe\",\n          \"Other\"\n        ]\n      }\n    },\n    \"meta\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"authors\": {\n          \"type\": \"array\",\n          \"minItems\": 1,\n          \"uniqueItems\": true,\n          \"items\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n        },\n        \"createDate\": { \"$ref\": \"definitions.json#/isoDateString\" },\n        \"lastModifyDate\": { \"$ref\": \"definitions.json#/isoDateString\" },\n        \"importPlugin\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"plugin\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n            \"date\": { \"$ref\": \"definitions.json#/isoDateString\" },\n            \"comment\": { \"$ref\": \"definitions.json#/nonEmptyMultilineString\" }\n          },\n          \"required\": [\"plugin\", \"date\"],\n          \"additionalProperties\": false\n        }\n      },\n      \"required\": [\"authors\", \"createDate\", \"lastModifyDate\"],\n      \"additionalProperties\": false\n    },\n    \"comment\": { \"$ref\": \"definitions.json#/nonEmptyMultilineString\" },\n    \"links\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"manual\": { \"$ref\": \"definitions.json#/urlArray\" },\n        \"productPage\": { \"$ref\": \"definitions.json#/urlArray\" },\n        \"video\": { \"$ref\": \"definitions.json#/urlArray\" },\n        \"other\": { \"$ref\": \"definitions.json#/urlArray\" }\n      },\n      \"anyOf\": [\n        { \"required\": [\"manual\"] },\n        { \"required\": [\"productPage\"] },\n        { \"required\": [\"video\"] },\n        { \"required\": [\"other\"] }\n      ],\n      \"additionalProperties\": false\n    },\n    \"helpWanted\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n    \"rdm\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"modelId\": {\n          \"type\": \"integer\",\n          \"minimum\": 0,\n          \"maximum\": 65535\n        },\n        \"softwareVersion\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n      },\n      \"required\": [\"modelId\"],\n      \"additionalProperties\": false\n    },\n    \"physical\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"properties\": {\n        \"dimensions\": {\n          \"$ref\": \"definitions.json#/dimensionsXYZ\"\n        },\n        \"weight\": {\n          \"description\": \"in kg\",\n          \"type\": \"number\",\n          \"exclusiveMinimum\": 0\n        },\n        \"power\": {\n          \"description\": \"in W\",\n          \"type\": \"number\",\n          \"exclusiveMinimum\": 0\n        },\n        \"powerConnectors\": {\n          \"type\": \"object\",\n          \"minProperties\": 1,\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"IEC C13\": {\n              \"$ref\": \"definitions.json#/powerConnectorType\"\n            },\n            \"IEC C19\": {\n              \"type\": \"string\",\n              \"const\": \"input only\"\n            },\n            \"powerCON\": {\n              \"$ref\": \"definitions.json#/powerConnectorType\"\n            },\n            \"powerCON TRUE1\": {\n              \"$ref\": \"definitions.json#/powerConnectorType\"\n            },\n            \"powerCON TRUE1 TOP\": {\n              \"$ref\": \"definitions.json#/powerConnectorType\"\n            },\n            \"powerCON 32 A\": {\n              \"type\": \"string\",\n              \"const\": \"input only\"\n            },\n            \"Hardwired\": {\n              \"$ref\": \"definitions.json#/powerConnectorType\"\n            },\n            \"Proprietary\": {\n              \"$ref\": \"definitions.json#/powerConnectorType\"\n            }\n          }\n        },\n        \"DMXconnector\": {\n          \"$comment\": \"additions are welcome\",\n          \"enum\": [\n            \"3-pin\",\n            \"3-pin (swapped +/-)\",\n            \"3-pin XLR IP65\",\n            \"5-pin\",\n            \"5-pin XLR IP65\",\n            \"3-pin and 5-pin\",\n            \"3.5mm stereo jack\",\n            \"RJ45\"\n          ]\n        },\n        \"bulb\": {\n          \"type\": \"object\",\n          \"minProperties\": 1,\n          \"properties\": {\n            \"type\": {\n              \"description\": \"e.g. 'LED'\",\n              \"$ref\": \"definitions.json#/nonEmptyString\"\n            },\n            \"colorTemperature\": {\n              \"description\": \"in K\",\n              \"type\": \"number\",\n              \"exclusiveMinimum\": 0\n            },\n            \"lumens\": {\n              \"type\": \"number\",\n              \"exclusiveMinimum\": 0\n            }\n          },\n          \"additionalProperties\": false\n        },\n        \"lens\": {\n          \"type\": \"object\",\n          \"minProperties\": 1,\n          \"properties\": {\n            \"name\": {\n              \"description\": \"e.g. 'PC', 'Fresnel'\",\n              \"$ref\": \"definitions.json#/nonEmptyString\"\n            },\n            \"degreesMinMax\": {\n              \"type\": \"array\",\n              \"minItems\": 2,\n              \"maxItems\": 2,\n              \"items\": {\n                \"type\": \"number\",\n                \"minimum\": 0,\n                \"maximum\": 360\n              }\n            }\n          },\n          \"additionalProperties\": false\n        },\n        \"matrixPixels\": {\n          \"type\": \"object\",\n          \"minProperties\": 1,\n          \"properties\": {\n            \"dimensions\": { \"$ref\": \"definitions.json#/dimensionsXYZ\" },\n            \"spacing\": { \"$ref\": \"definitions.json#/dimensionsXYZ\" }\n          },\n          \"additionalProperties\": false\n        }\n      },\n      \"additionalProperties\": false\n    },\n    \"matrix\": { \"$ref\": \"matrix.json#\" },\n    \"wheels\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"propertyNames\": {\n        \"$comment\": \"wheel names\",\n        \"$ref\": \"definitions.json#/nonEmptyString\"\n      },\n      \"additionalProperties\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"direction\": { \"enum\": [\"CW\", \"CCW\"] },\n          \"slots\": {\n            \"type\": \"array\",\n            \"minItems\": 2,\n            \"items\": { \"$ref\": \"wheel-slot.json#\" }\n          }\n        },\n        \"required\": [\"slots\"],\n        \"additionalProperties\": false\n      }\n    },\n    \"availableChannels\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"propertyNames\": {\n        \"$comment\": \"channel keys\",\n        \"$ref\": \"definitions.json#/noVariablesString\"\n      },\n      \"additionalProperties\": { \"$ref\": \"channel.json#\" }\n    },\n    \"templateChannels\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"propertyNames\": {\n        \"$comment\": \"template channel keys\",\n        \"$ref\": \"definitions.json#/variablePixelKeyString\"\n      },\n      \"additionalProperties\": { \"$ref\": \"channel.json#\" }\n    },\n    \"modes\": {\n      \"type\": \"array\",\n      \"minItems\": 1,\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"name\": { \"$ref\": \"definitions.json#/modeNameString\" },\n          \"shortName\": { \"$ref\": \"definitions.json#/modeNameString\" },\n          \"rdmPersonalityIndex\": {\n            \"type\": \"integer\",\n            \"minimum\": 1\n          },\n          \"physical\": { \"$ref\": \"#/properties/physical\" },\n          \"channels\": {\n            \"type\": \"array\",\n            \"minItems\": 1,\n            \"items\": {\n              \"oneOf\": [\n                {\n                  \"$comment\": \"for unused channels\",\n                  \"type\": \"null\"\n                },\n                {\n                  \"$comment\": \"normal channel keys, resolved template channel keys or channel alias keys\",\n                  \"$ref\": \"definitions.json#/noVariablesString\"\n                },\n                {\n                  \"$comment\": \"matrix channel insert block\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"insert\": { \"const\": \"matrixChannels\" },\n                    \"repeatFor\": {\n                      \"oneOf\": [\n                        {\n                          \"enum\": [\n                            \"eachPixelABC\",\n                            \"eachPixelXYZ\",\n                            \"eachPixelXZY\",\n                            \"eachPixelYXZ\",\n                            \"eachPixelYZX\",\n                            \"eachPixelZXY\",\n                            \"eachPixelZYX\",\n                            \"eachPixelGroup\"\n                          ]\n                        },\n                        {\n                          \"type\": \"array\",\n                          \"minItems\": 1,\n                          \"uniqueItems\": true,\n                          \"items\": {\n                            \"$comment\": \"pixel key or pixel group key\",\n                            \"$ref\": \"definitions.json#/noVariablesString\"\n                          }\n                        }\n                      ]\n                    },\n                    \"channelOrder\": { \"enum\": [\"perPixel\", \"perChannel\"] },\n                    \"templateChannels\": {\n                      \"type\": \"array\",\n                      \"minItems\": 1,\n                      \"items\": {\n                        \"oneOf\": [\n                          {\n                            \"$comment\": \"for unused channels\",\n                            \"type\": \"null\"\n                          },\n                          {\n                            \"$comment\": \"template channel key or template channel alias key\",\n                            \"$ref\": \"definitions.json#/variablePixelKeyString\"\n                          }\n                        ]\n                      }\n                    }\n                  },\n                  \"required\": [\"insert\", \"repeatFor\", \"channelOrder\", \"templateChannels\"],\n                  \"additionalProperties\": false\n                }\n              ]\n            }\n          }\n        },\n        \"required\": [\"name\", \"channels\"],\n        \"additionalProperties\": false\n      }\n    }\n  },\n  \"dependencies\": {\n    \"matrix\": [\"templateChannels\"],\n    \"templateChannels\": [\"matrix\"]\n  },\n  \"required\": [\"$schema\", \"name\", \"categories\", \"meta\", \"modes\"],\n  \"allOf\": [\n    {\n      \"if\": {\n        \"properties\": { \"modes\": { \"contains\": { \"required\": [\"rdmPersonalityIndex\"] } } }\n      },\n      \"then\": {\n        \"required\": [\"rdm\"]\n      }\n    },\n    {\n      \"anyOf\": [\n        { \"required\": [\"availableChannels\"] },\n        { \"required\": [\"templateChannels\"] }\n      ]\n    }\n  ],\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "schemas/gobo.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\",\n\n  \"version\": \"12.5.0\",\n\n  \"type\": \"object\",\n  \"properties\": {\n    \"$schema\": {\n      \"const\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/gobo.json\"\n    },\n    \"name\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n    \"keywords\": {\n      \"description\": \"Space-separated list of lowercase words describing the gobo.\",\n      \"type\": \"string\",\n      \"pattern\": \"^[a-z]+( [a-z]+)*$\"\n    },\n    \"source\": {\n      \"description\": \"An URL or text describing where the gobo was extracted from.\",\n      \"anyOf\": [\n        { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        { \"$ref\": \"definitions.json#/urlString\" }\n      ]\n    }\n  },\n  \"additionalProperties\": false,\n  \"required\": [\"$schema\", \"name\"]\n}\n"
  },
  {
    "path": "schemas/manufacturers.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/manufacturers.json\",\n\n  \"version\": \"12.5.0\",\n\n  \"type\": \"object\",\n  \"properties\": {\n    \"$schema\": {\n      \"const\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/manufacturers.json\"\n    }\n  },\n  \"required\": [\"$schema\"],\n  \"propertyNames\": {\n    \"$comment\": \"manufacturer key\",\n    \"type\": \"string\",\n    \"pattern\": \"^[a-z0-9\\\\-]+$|^\\\\$\"\n  },\n  \"additionalProperties\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"name\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n      \"comment\": { \"$ref\": \"definitions.json#/nonEmptyMultilineString\" },\n      \"website\": { \"$ref\": \"definitions.json#/urlString\" },\n      \"rdmId\": {\n        \"type\": \"integer\",\n        \"minimum\": 1,\n        \"maximum\": 32767\n      }\n    },\n    \"required\": [\"name\"],\n    \"additionalProperties\": false\n  }\n}\n"
  },
  {
    "path": "schemas/matrix.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/matrix.json\",\n\n  \"$comment\": \"This file is used by another schema file and should not be used directly as a JSON schema.\",\n\n  \"definitions\": {\n    \"pixelNumberConstraintArray\": {\n      \"type\": \"array\",\n      \"minItems\": 1,\n      \"uniqueItems\": true,\n      \"items\": { \"$ref\": \"#/definitions/pixelNumberConstraint\" }\n    },\n    \"pixelNumberConstraint\": {\n      \"oneOf\": [\n        {\n          \"$comment\": \"exact position\",\n          \"type\": \"string\",\n          \"pattern\": \"^=[1-9][0-9]*$\"\n        },\n        {\n          \"$comment\": \"minimum position\",\n          \"type\": \"string\",\n          \"pattern\": \"^>=[1-9][0-9]*$\"\n        },\n        {\n          \"$comment\": \"maximum position\",\n          \"type\": \"string\",\n          \"pattern\": \"^<=[1-9][0-9]*$\"\n        },\n        {\n          \"$comment\": \"position divisible by number\",\n          \"type\": \"string\",\n          \"pattern\": \"^[1-9][0-9]*n$\"\n        },\n        {\n          \"$comment\": \"position divisible by number with remainder\",\n          \"type\": \"string\",\n          \"pattern\": \"^[1-9][0-9]*n\\\\+[1-9][0-9]*$\"\n        },\n        {\n          \"const\": \"even\"\n        },\n        {\n          \"const\": \"odd\"\n        }\n      ]\n    }\n  },\n\n  \"type\": \"object\",\n  \"properties\": {\n    \"pixelCount\": {\n      \"description\": \"amount of pixels in X, Y and Z directions\",\n      \"type\": \"array\",\n      \"minItems\": 3,\n      \"maxItems\": 3,\n      \"items\": {\n        \"type\": \"integer\",\n        \"minimum\": 1\n      }\n    },\n    \"pixelKeys\": {\n      \"description\": \"pixelKeys in a structure of arrays for the Z, Y and X directions\",\n      \"type\": \"array\",\n      \"minItems\": 1,\n      \"items\": {\n        \"type\": \"array\",\n        \"minItems\": 1,\n        \"items\": {\n          \"type\": \"array\",\n          \"minItems\": 1,\n          \"items\": {\n            \"oneOf\": [\n              { \"$ref\": \"definitions.json#/noVariablesString\" },\n              { \"type\": \"null\" }\n            ]\n          }\n        }\n      }\n    },\n    \"pixelGroups\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"propertyNames\": {\n        \"$comment\": \"pixel group keys\",\n        \"$ref\": \"definitions.json#/noVariablesString\"\n      },\n      \"additionalProperties\": {\n        \"oneOf\": [\n          {\n            \"$comment\": \"specify pixel keys directly\",\n            \"type\": \"array\",\n            \"minItems\": 1,\n            \"uniqueItems\": true,\n            \"items\": {\n              \"$ref\": \"definitions.json#/noVariablesString\"\n            }\n          },\n          {\n            \"const\": \"all\"\n          },\n          {\n            \"$comment\": \"pixel key constraints\",\n            \"type\": \"object\",\n            \"minProperties\": 1,\n            \"properties\": {\n              \"x\": { \"$ref\": \"#/definitions/pixelNumberConstraintArray\" },\n              \"y\": { \"$ref\": \"#/definitions/pixelNumberConstraintArray\" },\n              \"z\": { \"$ref\": \"#/definitions/pixelNumberConstraintArray\" },\n              \"name\": {\n                \"type\": \"array\",\n                \"minItems\": 1,\n                \"uniqueItems\": true,\n                \"items\": {\n                  \"$comment\": \"pattern that pixel keys should match\",\n                  \"type\": \"string\",\n                  \"minLength\": 1,\n                  \"format\": \"regex\"\n                }\n              }\n            },\n            \"additionalProperties\": false\n          }\n        ]\n      }\n    }\n  },\n  \"oneOf\": [\n    { \"required\": [\"pixelCount\"] },\n    { \"required\": [\"pixelKeys\"] }\n  ],\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "schemas/plugin.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n\n  \"definitions\": {\n    \"htmlStringLines\": {\n      \"description\": \"HTML string lines, will be joined by \\\\n.\",\n      \"type\": \"array\",\n      \"minItems\": 1,\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"urlString\": {\n      \"type\": \"string\",\n      \"pattern\": \"^(ftp|http|https)://[^ \\\"]+$\",\n      \"format\": \"uri\"\n    },\n    \"fileLocations\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"properties\": {\n        \"main\": { \"type\": \"string\" },\n        \"user\": { \"type\": \"string\" }\n      },\n      \"additionalProperties\": false\n    }\n  },\n\n  \"type\": \"object\",\n  \"properties\": {\n    \"$schema\": { \"const\": \"../../schemas/plugin.json\" },\n    \"name\": {\n      \"type\": \"string\"\n    },\n    \"previousVersions\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"additionalProperties\": {\n        \"type\": \"string\"\n      }\n    },\n    \"description\": { \"$ref\": \"#/definitions/htmlStringLines\" },\n    \"links\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"additionalProperties\": { \"$ref\": \"#/definitions/urlString\" },\n      \"default\": {\n        \"Website\": \"\",\n        \"Fixture library download\": \"\",\n        \"Fixture format documentation\": \"\"\n      }\n    },\n    \"fixtureUsage\": { \"$ref\": \"#/definitions/htmlStringLines\" },\n    \"fileLocations\": {\n      \"type\": \"object\",\n      \"minProperties\": 1,\n      \"properties\": {\n        \"subDirectoriesAllowed\": {\n          \"type\": \"boolean\"\n        }\n      },\n      \"additionalProperties\": { \"$ref\": \"#/definitions/fileLocations\" },\n      \"default\": {\n        \"Windows\": \"\",\n        \"Mac OS\": \"\",\n        \"Linux\": \"\"\n      }\n    },\n    \"additionalInfo\": { \"$ref\": \"#/definitions/htmlStringLines\" },\n    \"helpWanted\": { \"type\": \"string\" }\n  },\n  \"required\": [\"$schema\", \"name\", \"description\", \"links\"],\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "schemas/wheel-slot.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/wheel-slot.json\",\n\n  \"$comment\": \"This file is used by another schema file and should not be used directly as a JSON schema.\",\n\n  \"type\": \"object\",\n  \"discriminator\": { \"propertyName\": \"type\" },\n  \"oneOf\": [\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"Open\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"Closed\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"Color\" },\n        \"name\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"colors\": {\n          \"type\": \"array\",\n          \"minItems\": 1,\n          \"items\": { \"$ref\": \"definitions.json#/colorString\" }\n        },\n        \"colorTemperature\": { \"$ref\": \"definitions.json#/entities/colorTemperature\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"Gobo\" },\n        \"resource\": { \"$ref\": \"definitions.json#/goboResourceString\" },\n        \"name\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"Prism\" },\n        \"name\": { \"$ref\": \"definitions.json#/nonEmptyString\" },\n        \"facets\": {\n          \"type\": \"integer\",\n          \"minimum\": 2\n        }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"Iris\" },\n        \"openPercent\": { \"$ref\": \"definitions.json#/entities/irisPercent\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"Frost\" },\n        \"frostIntensity\": { \"$ref\": \"definitions.json#/entities/percent\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"AnimationGoboStart\" },\n        \"name\": { \"$ref\": \"definitions.json#/nonEmptyString\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    },\n    {\n      \"properties\": {\n        \"type\": { \"const\": \"AnimationGoboEnd\" }\n      },\n      \"required\": [\"type\"],\n      \"additionalProperties\": false\n    }\n  ]\n}\n"
  },
  {
    "path": "server/ecosystem.config.js",
    "content": "// pm2 is expected to be installed globally\n\nconst secrets = require('./ofl-secrets.json');\n\nconst environmentVariablesOfl = {\n  ALLOW_SEARCH_INDEXING: 'allowed',\n  GITHUB_USER_TOKEN: secrets.OFL_GITHUB_USER_TOKEN,\n  NODE_ENV: 'production',\n  PORT: '5000',\n  WEBSITE_URL: 'https://open-fixture-library.org/',\n};\n\nconst environmentVariablesEmbetty = {\n  PORT: '6977',\n  VALID_ORIGINS: '*', // access control is implemented in nginx reverse proxy\n};\n\nmodule.exports = {\n  /**\n   * Application configuration section\n   * https://pm2.keymetrics.io/docs/usage/application-declaration/\n   */\n  apps: [\n    {\n      name: 'ofl',\n      script: './node_modules/nuxt/bin/nuxt.js',\n      args: 'start',\n      cwd: '/home/flo/open-fixture-library',\n      // eslint-disable-next-line camelcase -- required by PM2\n      log_date_format: 'YYYY-MM-DD HH:mm:ss Z',\n      env: environmentVariablesOfl,\n    },\n    {\n      name: 'webhook',\n      script: 'webhook.js',\n      cwd: '/home/flo',\n      // eslint-disable-next-line camelcase -- required by PM2\n      log_date_format: 'YYYY-MM-DD HH:mm:ss Z',\n    },\n    {\n      name: 'embetty',\n      script: './node_modules/@heise/embetty-server/bin/embetty-start',\n      cwd: '/home/flo/open-fixture-library',\n      // eslint-disable-next-line camelcase -- required by PM2\n      log_date_format: 'YYYY-MM-DD HH:mm:ss Z',\n      env: environmentVariablesEmbetty,\n    },\n  ],\n};\n"
  },
  {
    "path": "server/nginx-site-available",
    "content": "##\n# You should look at the following URL's in order to grasp a solid understanding\n# of Nginx configuration files in order to fully unleash the power of Nginx.\n# https://wiki.nginx.org/Pitfalls\n# https://wiki.nginx.org/QuickStart\n# https://wiki.nginx.org/Configuration\n#\n# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.\n#\n# Test the configuration with `nginx -t`\n# before restarting with `systemctl restart nginx`\n##\n\n\n# requests to https://open-fixture-library.org (without subdomain)\n# proxied to http://localhost:5000\nserver {\n    listen 443 ssl http2;\n    listen [::]:443 ssl http2;\n\n    server_name open-fixture-library.org;\n    server_tokens off;\n\n    ssl_certificate /etc/letsencrypt/live/open-fixture-library.org/fullchain.pem; # managed by Certbot\n    ssl_certificate_key /etc/letsencrypt/live/open-fixture-library.org/privkey.pem; # managed by Certbot\n    # include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot\n    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot\n\n    # from https://github.com/certbot/certbot/blob/v1.5.0/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf\n    ssl_session_cache shared:le_nginx_SSL:10m;\n    ssl_session_timeout 1440m;\n    ssl_session_tickets off;\n    ssl_protocols TLSv1.2 TLSv1.3;\n    ssl_prefer_server_ciphers off;\n    ssl_ciphers \"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384\";\n\n    # drop connection for all subdomains (if not handled elsewhere anyway)\n    if ($host != open-fixture-library.org) {\n        return 444;\n    }\n\n    location / {\n        proxy_pass http://localhost:5000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection 'upgrade';\n        proxy_set_header Host $host;\n        proxy_cache_bypass $http_upgrade;\n    }\n}\n\n\n# redirect HTTPS requests from www subdomain to main domain\nserver {\n    listen 443 ssl http2;\n    listen [::]:443 ssl http2;\n\n    server_name www.open-fixture-library.org;\n    server_tokens off;\n\n    return 301 https://open-fixture-library.org$request_uri;\n}\n\n\n# all HTTP requests that don't match another rule\nserver {\n    listen 80 default_server;\n    listen [::]:80;\n\n    server_name _;\n    server_tokens off;\n\n    # drop connection\n    return 444;\n}\n\n\n# redirect requests to http://[www.]open-fixture-library.org to HTTPS version\n# No canonicalization steps are taken yet.\n# See https://www.sentinelstand.com/article/http-strict-transport-security-hsts-canonical-www-redirects\nserver {\n    listen 80;\n    listen [::]:80;\n\n    server_name open-fixture-library.org www.open-fixture-library.org;\n    server_tokens off;\n\n    return 301 https://$host$request_uri;\n}\n\n\n# requests to https://webhooks.open-fixture-library.org\n# proxied to http://localhost:40010\nserver {\n    listen [::]:443 ssl http2;\n    listen 443 ssl http2;\n\n    server_name webhooks.open-fixture-library.org;\n    server_tokens off;\n\n    location / {\n        proxy_pass http://localhost:40010;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection 'upgrade';\n        proxy_set_header Host $host;\n        proxy_cache_bypass $http_upgrade;\n    }\n}\n\n\n# requests to https://embetty.open-fixture-library.org\n# proxied to http://localhost:6977\nserver {\n    listen [::]:443 ssl http2;\n    listen 443 ssl http2;\n\n    server_name embetty.open-fixture-library.org;\n    server_tokens off;\n\n    location / {\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection 'upgrade';\n        proxy_set_header Host $host;\n        proxy_cache_bypass $http_upgrade;\n\n        # if request does not have an \"Origin\" HTTP header (only sent from within fetch / XHR requests)\n        if ($http_origin = '') {\n            set $cors 'allowed';\n        }\n\n        # if request comes from one of these allowed domains:\n        # - https://open-fixture-library.org\n        # - https://*.open-fixture-library.org\n        # - localhost on any port, http and https\n        # (see https://regex101.com/r/uit4OY/1)\n        if ($http_origin ~* (^(?:https:\\/\\/(?:[a-z0-9_-]+\\.)?open-fixture-library\\.org|https?:\\/\\/localhost)(?::\\d+)?$)) {\n            set $cors 'allowed';\n        }\n\n        if ($cors != 'allowed') {\n            add_header 'Access-Control-Allow-Origin' 'https://open-fixture-library.org' always;\n            add_header 'Vary' 'Origin' always;\n            return 403;\n        }\n\n        proxy_pass http://localhost:6977;\n    }\n}\n"
  },
  {
    "path": "server/redeploy.sh",
    "content": "#!/bin/bash\n\n# Exit immediately when one command fails\nset -e\n\n# Echo each command before executing\ntrap 'echo \"# $(date --iso-8601=seconds): $BASH_COMMAND\"' DEBUG\n\ncd /home/flo/open-fixture-library\n\ngit pull -p\nnpm ci --include=dev\nnpm run build\n\nif [ -e ./server ]; then\n  cp ./server/* /home/flo\nfi\n\npm2 reload /home/flo/ecosystem.config.js\n"
  },
  {
    "path": "server/webhook.js",
    "content": "#!/usr/bin/env node\n\n// crypto is expected to be installed globally\n\nconst { execSync } = require('child_process');\nconst { createHmac, timingSafeEqual } = require('crypto');\nconst http = require('http');\nconst pm2config = require('./ecosystem.config.js');\nconst secrets = require('./ofl-secrets.json');\n\nconst pm2AppConfig = pm2config.apps.find((app) => app.name === 'ofl');\n\nconst deploymentConfig = {\n  env: pm2AppConfig.env,\n  action: '',\n  webhookPort: 40_010,\n  webhookPath: '/',\n  webhookSecret: secrets.OFL_WEBHOOK_SECRET,\n};\n\nstartServer()\n  .then(() => console.log('Exited'))\n  .catch((error) => console.error('Exited with error', error));\n\n/**\n * @returns {Promise} Promise that resolves/rejects when the server process terminates.\n */\nfunction startServer() {\n  const port = deploymentConfig.webhookPort;\n\n  console.log(`Starting webhook listener on port ${port}`);\n\n  return new Promise((resolve, reject) => {\n    http.createServer((request, response) => {\n      response.writeHead(200, { 'Content-Type': 'text/plain' });\n      response.write('Received');\n      response.end();\n\n      if (request.method !== 'POST') {\n        return;\n      }\n\n      const bodyChunks = [];\n      let totalSize = 0;\n      request.on('data', (data) => {\n        bodyChunks.push(data);\n        totalSize += data.length;\n        if (totalSize > 1e6) { // 1MB limit\n          request.destroy(new Error('Request body too large'));\n        }\n      }).on('end', () => {\n        const body = Buffer.concat(bodyChunks);\n        processRequest(request.url, body, request.headers);\n      });\n    }).on('close', resolve).on('error', reject).listen(port);\n  });\n}\n\n/**\n * Handle a received request from the server and check if it is valid. If so,\n * call {@link redeploy} to update the corresponding app.\n *\n * @param {string} url The absolute path the request was received at.\n * @param {Buffer} body The raw body from GitHub.\n * @param {Record<string, string>} headers Headers of the request.\n */\nfunction processRequest(url, body, headers) {\n  console.log(`Received webhook request at ${url}`);\n\n  if (deploymentConfig.webhookPath !== url) {\n    return;\n  }\n\n  const hmac = createHmac('sha256', deploymentConfig.webhookSecret);\n  hmac.update(body);\n\n  const xub = 'X-Hub-Signature-256';\n  const received = Buffer.from(headers[xub] || headers[xub.toLowerCase()] || '');\n  const digest = hmac.digest('hex');\n  const expected = Buffer.from(`sha256=${digest}`);\n\n  if (received.length !== expected.length || !timingSafeEqual(received, expected)) {\n    const expectedString = expected.toString('utf-8');\n    const receivedString = received.toString('utf-8');\n    console.error(`Wrong secret: Expected '${expectedString}', received '${receivedString}'`);\n    return;\n  }\n\n  console.info('Secret test passed');\n\n  const eventName = headers['X-GitHub-Event'] || headers['x-github-event'];\n  if (eventName !== 'push') {\n    console.log(`Wrong event name: Expected 'push', received '${eventName}'`);\n    return;\n  }\n\n  const json = JSON.parse(body.toString('utf-8'));\n\n  if (json.ref !== 'refs/heads/master') {\n    console.log(`Wrong branch: Expected 'refs/heads/master', received '${json.ref}'`);\n    return;\n  }\n\n  console.log(`Redeploy because of commit ${json.head_commit.id}: '${json.head_commit.message}'`);\n\n  redeploy(json);\n}\n\n/**\n * Calls redeploy bash script and notify admin via email if script fails.\n * @param {object} webhookPayload The data delivered by GitHub via the webhook.\n */\nfunction redeploy(webhookPayload) {\n  try {\n    execSync('./redeploy.sh', {\n      cwd: '/home/flo',\n      env: { ...process.env, ...deploymentConfig.env },\n      encoding: 'utf-8',\n      stdio: 'pipe',\n    });\n    console.log('Successfully deployed.');\n  }\n  catch (error) {\n    console.log(`Redeploy process failed with exit code ${error.status}.`);\n    console.log('Notify admin via email about failed deployment...');\n\n    const subject = 'OFL Deployment failed';\n    let body = new Date().toISOString();\n    body += `\\n\\nsubprocess status: ${error.status}, signal: ${error.signal}`;\n    body += `\\n\\nsubprocess stdout:\\n${error.stdout}`;\n    body += `\\n\\nsubprocess stderr:\\n${error.stderr}`;\n    body += `\\n\\nwebhook payload: ${JSON.stringify(webhookPayload, null, 2)}`;\n\n    execSync(`mail -s \"${subject}\" root`, {\n      input: body,\n    });\n  }\n}\n"
  },
  {
    "path": "tests/built-files-committed.js",
    "content": "#!/usr/bin/env node\n\nimport childProcess from 'child_process';\nimport { fileURLToPath } from 'url';\nimport { styleText } from 'util';\n\nconst projectDirectory = fileURLToPath(new URL('../', import.meta.url));\n\ntry {\n  childProcess.execSync('npm run build', {\n    cwd: projectDirectory,\n  });\n}\ncatch (error) {\n  console.error(styleText('red', '[FAIL]'), 'Unable to run `npm run build` command:', error);\n  process.exit(1);\n}\n\n// check whether there are unstaged changes (probably created by building before)\nconst result = childProcess.spawnSync('git diff --exit-code', {\n  cwd: projectDirectory,\n  shell: true,\n  stdio: 'inherit',\n});\nconsole.log('\\n');\n\nif (result.status !== 0) {\n  console.error(styleText('red', '[FAIL]'), 'Built files (or other changes) are not committed. Please run `npm run build` and stage (git add) all changes.');\n  process.exit(1);\n}\n\nconsole.log(styleText('green', '[PASS]'), 'Built files are committed.');\nprocess.exit(0);\n"
  },
  {
    "path": "tests/dmx-value-scaling.test.js",
    "content": "import { describe, expect, it } from 'vitest';\nimport {\n  scaleDmxRange,\n  scaleDmxValue,\n} from '../lib/scale-dmx-values.js';\n\ndescribe('scaleDmxValue', () => {\n  describe('8bit → 16bit', () => {\n    it.each`\n      dmxValue |  expected | comment\n          ${0} |      ${0} | ${'[  0] → [  0,   0]'}\n        ${127} | ${32_639} | ${'[127] → [127, 127]'}\n        ${255} | ${65_535} | ${'[255] → [255, 255] = 256^2 - 1'}\n    `('scaleDmxValue($dmxValue, 1, 2) should be $expected', ({ dmxValue, expected }) => {\n      expect(scaleDmxValue(dmxValue, 1, 2)).toBe(expected);\n    });\n  });\n\n  describe('8bit → 24bit', () => {\n    it.each`\n      dmxValue |      expected | comment\n          ${0} |          ${0} | ${'[  0] → [  0,   0,   0]'}\n        ${127} |  ${8_355_711} | ${'[127] → [127, 127, 127]'}\n        ${128} |  ${8_421_504} | ${'[128] → [128, 128, 128]'}\n        ${255} | ${16_777_215} | ${'[255] → [255, 255, 255] = 256^3 - 1'}\n    `('scaleDmxValue($dmxValue, 1, 3) should be $expected', ({ dmxValue, expected }) => {\n      expect(scaleDmxValue(dmxValue, 1, 3)).toBe(expected);\n    });\n  });\n\n  describe('16bit → 24bit', () => {\n    it.each`\n       dmxValue |      expected | comment\n           ${0} |          ${0} | ${'[  0,   0] → [  0,   0,   0]'}\n         ${255} |     ${65_535} | ${'[  0, 255] → [  0, 255, 255]'}\n         ${256} |     ${65_536} | ${'[  1,   0] → [  1,   0,   0]'}\n      ${32_767} |  ${8_388_607} | ${'[127, 255] → [127, 255, 255]'}\n      ${32_768} |  ${8_388_608} | ${'[128,   0] → [128,   0,   0]'}\n      ${65_279} | ${16_711_679} | ${'[254, 255] → [254, 255, 255]'}\n      ${65_280} | ${16_711_680} | ${'[255,   0] → [255,   0,   0]'}\n      ${65_535} | ${16_777_215} | ${'[255, 255] → [255, 255, 255]'}\n    `('scaleDmxValue($dmxValue, 2, 3) should be $expected', ({ dmxValue, expected }) => {\n      expect(scaleDmxValue(dmxValue, 2, 3)).toBe(expected);\n    });\n  });\n\n  describe('16bit → 8bit', () => {\n    it.each`\n       dmxValue | expected | comment\n           ${0} |     ${0} | ${'[  0,   0] → [  0]'}\n      ${32_512} |   ${127} | ${'[127,   0] → [127]'}\n      ${32_639} |   ${127} | ${'[127, 127] → [127]'}\n      ${32_767} |   ${127} | ${'[127, 255] → [127]'}\n      ${32_768} |   ${128} | ${'[128,   0] → [128]'}\n      ${65_280} |   ${255} | ${'[255,   0] → [255]'}\n      ${65_535} |   ${255} | ${'[255, 255] → [255] = 256^2 - 1'}\n    `('scaleDmxValue($dmxValue, 2, 1) should be $expected', ({ dmxValue, expected }) => {\n      expect(scaleDmxValue(dmxValue, 2, 1)).toBe(expected);\n    });\n  });\n\n  describe('24bit → 8bit', () => {\n    it.each`\n           dmxValue | expected | comment\n               ${0} |     ${0} | ${'[  0,   0,   0] → [  0]'}\n          ${65_535} |     ${0} | ${'[  0, 255, 255] → [  0]'}\n          ${65_536} |     ${1} | ${'[  1,   0,   0] → [  1]'}\n       ${8_388_607} |   ${127} | ${'[127, 255, 255] → [127]'}\n       ${8_388_608} |   ${128} | ${'[128,   0,   0] → [128]'}\n      ${16_711_679} |   ${254} | ${'[254, 255, 255] → [254]'}\n      ${16_711_680} |   ${255} | ${'[255,   0,   0] → [255]'}\n      ${16_777_215} |   ${255} | ${'[255, 255, 255] → [255]'}\n    `('scaleDmxValue($dmxValue, 3, 1) should be $expected', ({ dmxValue, expected }) => {\n      expect(scaleDmxValue(dmxValue, 3, 1)).toBe(expected);\n    });\n  });\n\n  describe('24bit → 16bit', () => {\n    it.each`\n           dmxValue |  expected | comment\n               ${0} |      ${0} | ${'[  0,   0,   0] → [  0,   0]'}\n          ${65_535} |    ${255} | ${'[  0, 255, 255] → [  0, 255]'}\n          ${65_536} |    ${256} | ${'[  1,   0,   0] → [  1,   0]'}\n       ${8_388_352} | ${32_767} | ${'[127, 255,   0] → [127, 255]'}\n       ${8_388_607} | ${32_767} | ${'[127, 255, 255] → [127, 255]'}\n       ${8_388_608} | ${32_768} | ${'[128,   0,   0] → [128,   0]'}\n      ${16_711_679} | ${65_279} | ${'[254, 255, 255] → [254, 255]'}\n      ${16_711_680} | ${65_280} | ${'[255,   0,   0] → [255,   0]'}\n      ${16_711_935} | ${65_280} | ${'[255,   0, 255] → [255,   0]'}\n      ${16_777_215} | ${65_535} | ${'[255, 255, 255] → [255, 255]'}\n    `('scaleDmxValue($dmxValue, 3, 2) should be $expected', ({ dmxValue, expected }) => {\n      expect(scaleDmxValue(dmxValue, 3, 2)).toBe(expected);\n    });\n  });\n});\n\ndescribe('scaleDmxRange', () => {\n  describe('8bit → 16bit', () => {\n    it.each`\n       start |    end | scaledStart | scaledEnd\n        ${0} |   ${0} |        ${0} |    ${255}\n        ${0} | ${254} |        ${0} | ${65_279}\n        ${0} | ${255} |        ${0} | ${65_535}\n      ${127} | ${127} |   ${32_512} | ${32_767}\n      ${255} | ${255} |   ${65_280} | ${65_535}\n    `('scaleDmxRange([$start, $end], 1, 2) should be [$scaledStart, $scaledEnd]', ({ start, end, scaledStart, scaledEnd }) => {\n      expect(scaleDmxRange(start, end, 1, 2)).toStrictEqual([scaledStart, scaledEnd]);\n    });\n  });\n\n  describe('8bit → 24bit', () => {\n    it.each`\n       start |    end |   scaledStart |     scaledEnd\n        ${0} |   ${0} |          ${0} |     ${65_535}\n        ${0} | ${254} |          ${0} | ${16_711_679}\n        ${0} | ${255} |          ${0} | ${16_777_215}\n      ${127} | ${127} |  ${8_323_072} |  ${8_388_607}\n      ${255} | ${255} | ${16_711_680} | ${16_777_215}\n    `('scaleDmxRange([$start, $end], 1, 3) should be [$scaledStart, $scaledEnd]', ({ start, end, scaledStart, scaledEnd }) => {\n      expect(scaleDmxRange(start, end, 1, 3)).toStrictEqual([scaledStart, scaledEnd]);\n    });\n  });\n\n  describe('16bit → 8bit', () => {\n    it.each`\n          start |       end | scaledStart | scaledEnd\n           ${0} |    ${255} |        ${0} |      ${0}\n           ${0} |    ${100} |        ${0} |      ${0}\n         ${101} |    ${200} |        ${0} |      ${0}\n         ${201} |    ${300} |        ${1} |      ${1}\n           ${0} | ${65_535} |        ${0} |    ${255}\n      ${32_512} | ${32_767} |      ${127} |    ${127}\n      ${64_000} | ${65_279} |      ${250} |    ${254}\n      ${65_279} | ${65_535} |      ${255} |    ${255}\n      ${65_280} | ${65_535} |      ${255} |    ${255}\n    `('scaleDmxRange([$start, $end], 2, 1) should be [$scaledStart, $scaledEnd]', ({ start, end, scaledStart, scaledEnd }) => {\n      expect(scaleDmxRange(start, end, 2, 1)).toStrictEqual([scaledStart, scaledEnd]);\n    });\n  });\n\n  describe('24bit → 8bit', () => {\n    it.each`\n             start |          end | scaledStart | scaledEnd\n        ${615_605} | ${1_683_118} |       ${10} |     ${25}\n      ${1_683_119} | ${2_244_792} |       ${26} |     ${34}\n    `('scaleDmxRange([$start, $end], 3, 1) should be [$scaledStart, $scaledEnd]', ({ start, end, scaledStart, scaledEnd }) => {\n      expect(scaleDmxRange(start, end, 3, 1)).toStrictEqual([scaledStart, scaledEnd]);\n    });\n  });\n\n  describe('24bit → 16bit', () => {\n    it.each`\n             start |          end | scaledStart | scaledEnd\n        ${615_605} | ${1_683_118} |     ${2405} |   ${6574}\n      ${1_683_119} | ${2_244_792} |     ${6575} |   ${8768}\n    `('scaleDmxRange([$start, $end], 3, 2) should be [$scaledStart, $scaledEnd]', ({ start, end, scaledStart, scaledEnd }) => {\n      expect(scaleDmxRange(start, end, 3, 2)).toStrictEqual([scaledStart, scaledEnd]);\n    });\n  });\n});\n\ndescribe('random capabilities', () => {\n  it('scaled down from 16bit to 8bit do not overlap', () => {\n    const scaledRanges = getScaledDownRanges(2);\n    for (const [index, scaledRange] of scaledRanges.entries()) {\n      if (index === 0) {\n        continue;\n      }\n\n      const rangeStart = scaledRange[0];\n      const previousRangeEnd = scaledRanges[index - 1][1];\n      expect(rangeStart).toBeGreaterThan(previousRangeEnd);\n    }\n  });\n\n  it('scaled down from 24bit to 16bit do not overlap', () => {\n    const scaledRanges = getScaledDownRanges(3);\n    for (const [index, scaledRange] of scaledRanges.entries()) {\n      if (index === 0) {\n        continue;\n      }\n\n      const rangeStart = scaledRange[0];\n      const previousRangeEnd = scaledRanges[index - 1][1];\n      expect(rangeStart).toBeGreaterThan(previousRangeEnd);\n    }\n  });\n});\n\n/**\n * @param {number} resolution The resolution of the original ranges. Must be 2 or higher.\n * @returns {[number, number][]} List of adjacent [start, end] ranges, scaled down to the next-lower resolution.\n */\nfunction getScaledDownRanges(resolution) {\n  return getRandomCapabilityRanges(resolution).map(\n    ([start, end]) => scaleDmxRange(start, end, resolution, resolution - 1),\n  );\n}\n\n/**\n * @param {number} resolution The resolution (1 for 8bit, 2 for 16bit, etc.).\n * @returns {[number, number][]} Random list of adjacent capability [start, end] ranges. Together, they fill a whole channel.\n */\nfunction getRandomCapabilityRanges(resolution) {\n  const minimumRangeWidth = Math.pow(256, resolution - 1) - 1;\n  const maximumRangeWidth = minimumRangeWidth * 20;\n\n  const ranges = [];\n  let remainingDmxValues = Math.pow(256, resolution);\n  while (remainingDmxValues > 0) {\n    const rangeWidth = remainingDmxValues > maximumRangeWidth\n      ? Math.floor((Math.random() * (maximumRangeWidth - (2 * minimumRangeWidth))) + minimumRangeWidth)\n      : remainingDmxValues;\n\n    const lastDmxValue = ranges.length > 0 ? ranges.at(-1)[1] : -1;\n    ranges.push([lastDmxValue + 1, lastDmxValue + rangeWidth]);\n    remainingDmxValues -= rangeWidth;\n  }\n\n  return ranges;\n}\n"
  },
  {
    "path": "tests/external-links.js",
    "content": "#!/usr/bin/env node\n\nimport '../lib/load-env-file.js';\n\nimport http from 'http';\nimport https from 'https';\nimport { styleText } from 'util';\nimport { Octokit } from '@octokit/rest';\nimport SiteCrawler from '../lib/site-crawler.js';\n\nconst USER_AGENT = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0';\nconst GITHUB_COMMENT_HEADING = '## Broken links update';\nconst TIMEOUT = 30_000;\n\nconst excludedUrls = [\n  'https://open-fixture-library.org', // exclude canonical URLs\n  // eslint-disable-next-line sonarjs/no-clear-text-protocols -- not available as HTTPS\n  'http://rdm.openlighting.org/model/display', // exclude auto-generated URLs pointing to the Open Lighting RDM site as the fixture may not exist\n  'https://github.com/OpenLightingProject/open-fixture-library/', // exclude auto-generated URLs to GitHub as they are flaky and slow down the test\n  'https://web.archive.org/', // Wayback Machine links are designed to be available \"forever\" and we don't want to put unnecessary load on their servers.\n];\n\nconst testStartTime = Date.now();\nlet errored = false;\n\ntry {\n  const crawler = new SiteCrawler();\n\n  console.log(styleText(['blue', 'bold'], 'Starting OFL server ...'));\n  try {\n    await crawler.startServer();\n  }\n  catch (error) {\n    const header = styleText('redBright', 'Failed to start OFL server. Maybe you forgot running \\'npm run build\\' or there is already a running server?');\n    throw `${header} ${error.message}`;\n  }\n  console.log();\n\n  const externalUrlSet = new Set();\n\n  crawler.addEventListener('externalLinkFound', ({ url }) => {\n    if (!excludedUrls.some((excludedUrl) => url.startsWith(excludedUrl))) {\n      externalUrlSet.add(url);\n      process.stdout.write(`\\r${externalUrlSet.size} link(s) found.`);\n    }\n  });\n\n  const crawlStartTime = Date.now();\n  console.log(styleText(['blue', 'bold'], 'Start crawling the website for external links ...'));\n  await crawler.crawl();\n\n  const crawlTime = Date.now() - crawlStartTime;\n  console.log(`Crawling finished after ${crawlTime / 1000}s.`);\n  console.log();\n\n  const { stdout, stderr } = await crawler.stopServer();\n  if (stdout) {\n    console.log(styleText('blueBright', 'Server output (stdout):'));\n    console.log(stdout);\n  }\n  if (stderr) {\n    console.log(styleText('blueBright', 'Server errors (stderr):'));\n    console.log(stderr);\n  }\n\n  const urlResults = await fetchExternalUrls([...externalUrlSet]);\n  console.log();\n\n  console.log(styleText(['blue', 'bold'], 'Updating GitHub issue ...'));\n  await updateGithubIssue(urlResults);\n}\ncatch (error) {\n  console.error(error);\n  errored = true;\n}\n\nconst testTime = Date.now() - testStartTime;\nconsole.log();\nconsole.log(styleText(['greenBright', 'bold'], `Test took ${testTime / 1000}s.`));\nprocess.exit(errored ? 1 : 0);\n\n/**\n * @typedef {object} UrlResult\n * @property {string} url The requested URL.\n * @property {string} message User-visible information about the URL's status.\n * @property {boolean} failed Whether the requested URL can be seen as broken.\n */\n\n/**\n * Fetches the given URLs in small blocks that reduce the likelyhood of false negatives.\n * Pass / fail messages are constantly outputted to console.\n *\n * @param {string[]} externalUrls The URLs to fetch.\n * @returns {Promise<UrlResult[]>} The fetch results of the given URLs. Note that the order may (and probably will) be different.\n */\nasync function fetchExternalUrls(externalUrls) {\n  const urlResults = [];\n\n  // shuffle URLs so all requests to one domain are spread out in time\n  externalUrls.sort(() => Math.random() - 0.5);\n\n  const BLOCK_SIZE = 25;\n  const urlBlocks = Array.from(\n    { length: Math.ceil(externalUrls.length / BLOCK_SIZE) },\n    (_, index) => externalUrls.slice(index * BLOCK_SIZE, (index + 1) * BLOCK_SIZE),\n  );\n\n  console.log(styleText(['blue', 'bold'], `Start fetching ${externalUrls.length} external links in blocks of ${BLOCK_SIZE} URLs ...\\n`));\n  const fetchStartTime = Date.now();\n  for (const urlBlock of urlBlocks) {\n    await Promise.all(urlBlock.map(async (url) => {\n      const result = await testExternalLink(url);\n      urlResults.push(result);\n\n      const messageColor = result.failed ? 'redBright' : 'greenBright';\n      const coloredMessage = styleText(messageColor, result.message);\n      const coloredUrl = styleText('yellow', result.url);\n      console.log(`[${urlResults.length}/${externalUrls.length}: ${coloredMessage}] ${coloredUrl}`);\n    }));\n  }\n\n  // similar failing links (i.e. same domain) should be written under each other\n  urlResults.sort((a, b) => a.url.localeCompare(b.url));\n\n  const failingUrlResults = urlResults.filter((result) => result.failed);\n\n  const fetchTime = Date.now() - fetchStartTime;\n  const colonOrPeriod = failingUrlResults.length > 0 ? ':' : '.';\n  console.log(`\\nFetching done in ${fetchTime / 1000}s, ${failingUrlResults.length} of ${externalUrls.length} URLs have failed${colonOrPeriod}`);\n  for (const { url, message } of failingUrlResults) {\n    const coloredUrl = styleText('yellow', url);\n    const coloredMessage = styleText('redBright', message);\n    console.log(`- ${coloredUrl} (${coloredMessage})`);\n  }\n\n  return urlResults;\n}\n\n/**\n * @param {string} url The URL to check.\n * @returns {Promise<UrlResult>} Status of the checked url.\n */\nasync function testExternalLink(url) {\n  const httpModule = url.startsWith('https') ? https : http;\n\n  const resultHEAD = await getResult('HEAD');\n\n  if (resultHEAD.failed) {\n    return getResult('GET');\n  }\n  return resultHEAD;\n\n  /**\n   * @param {string} method The HTTP requests method, e.g. GET or HEAD.\n   * @returns {Promise<UrlResult>} Status of the url which has been requested with the given method.\n   */\n  function getResult(method) {\n    const requestOptions = {\n      method,\n      headers: {\n        'user-agent': USER_AGENT,\n      },\n      timeout: TIMEOUT,\n    };\n\n    return new Promise((resolve, reject) => {\n      const request = httpModule.get(url, requestOptions, (response) => {\n        resolve({\n          url,\n          message: `${response.statusCode} ${response.statusMessage}`,\n          failed: ![200, 302, 307].includes(response.statusCode),\n        });\n      });\n\n      request.on('timeout', () => {\n        resolve({\n          url,\n          message: `Timeout of ${requestOptions.timeout}ms exceeded.`,\n          failed: true,\n        });\n        request.abort();\n      });\n\n      request.on('error', (error) => {\n        resolve({\n          url,\n          message: error.message,\n          failed: true,\n        });\n      });\n    });\n  }\n}\n\n/**\n * Updates the GitHub issue for broken links.\n *\n * @param {UrlResult[]} urlResults Fetch results of all external URLs.\n * @returns {Promise} Promise that resolves when issue has been updated or rejects if the issue can't be updated.\n */\nasync function updateGithubIssue(urlResults) {\n  const requiredEnvironmentVariables = [\n    'GITHUB_USER_TOKEN',\n    'GITHUB_BROKEN_LINKS_ISSUE_NUMBER',\n    'GITHUB_REPOSITORY',\n    'GITHUB_RUN_ID',\n  ];\n\n  for (const environmentVariable of requiredEnvironmentVariables) {\n    if (!(environmentVariable in process.env)) {\n      console.log(`For updating GitHub issue, environment variable ${environmentVariable} is required. Please define it in your system or in the .env file.`);\n      return;\n    }\n  }\n\n  const workflowRunUrl = `https://github.com/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;\n\n  const githubClient = new Octokit({\n    auth: `token ${process.env.GITHUB_USER_TOKEN}`,\n  });\n\n  const [repoOwner, repoName] = process.env.GITHUB_REPOSITORY.split('/');\n\n  let issue;\n\n  try {\n    issue = await githubClient.rest.issues.get({\n      owner: repoOwner,\n      repo: repoName,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      issue_number: process.env.GITHUB_BROKEN_LINKS_ISSUE_NUMBER,\n    });\n  }\n  catch (error) {\n    throw `Can't access issue number ${process.env.GITHUB_BROKEN_LINKS_ISSUE_NUMBER}: ${error.message}. Please create it and leave the body empty.`;\n  }\n\n  const oldLinkData = getLinkDataFromBody(issue.data.body);\n  const newFailingUrlResults = [];\n  const fixedUrlResults = [];\n  const newLinkData = getUpdatedLinkData();\n  const deletedUrls = Object.keys(oldLinkData).filter((url) => !urlResults.some((result) => result.url === url));\n\n  console.log(`Updating GitHub issue body at https://github.com/${process.env.GITHUB_REPOSITORY}/issues/${process.env.GITHUB_BROKEN_LINKS_ISSUE_NUMBER}`);\n  await githubClient.rest.issues.update({\n    owner: repoOwner,\n    repo: repoName,\n    // eslint-disable-next-line camelcase -- required by GitHub API\n    issue_number: process.env.GITHUB_BROKEN_LINKS_ISSUE_NUMBER,\n    body: getBodyFromLinkData(newLinkData),\n  });\n\n  await deleteAutoGeneratedComments();\n  await createCommentIfNeeded();\n\n  /**\n   * @typedef {Record<string, LinkStatus[]>} LinkData URLs pointing to the last seven statuses.\n   */\n\n  /**\n   * @typedef {object} LinkStatus\n   * @property {boolean} failed Whether the requested URL can be seen as broken.\n   * @property {string | null} message User-visible information about the URL's status. May be null for passing links.\n   * @property {string | null} jobUrl Link to the workflow run page. May be null for passing links.\n   */\n\n  /**\n   * @param {string} body The current GitHub issue body.\n   * @returns {LinkData} The link data that is read from the body.\n   */\n  function getLinkDataFromBody(body) {\n    const linkData = {};\n\n    try {\n      const lines = body.split(/\\r?\\n/); // support both \\n and \\r\\n newline types\n      for (const line of lines) {\n        if (!line.startsWith('<tr><td nowrap>')) {\n          continue;\n        }\n\n        const [, lastResults, url] = line.match(/<tr><td nowrap>(.*?)<\\/td><td><a href=\"(.*?)\"/);\n\n        linkData[url] = lastResults.split('&nbsp;').map((item) => {\n          if (item === '✔️') {\n            return {\n              failed: false,\n              message: null,\n              jobUrl: null,\n            };\n          }\n\n          const [, jobUrl, message] = item.match(/<a href=\"(.*)\" title=\"(.*)\">[^<]+<\\/a>/);\n\n          return {\n            failed: true,\n            message,\n            jobUrl,\n          };\n        });\n      }\n    }\n    catch (error) {\n      throw new Error('Unable to retrieve link data from issue body', {\n        cause: error,\n      });\n    }\n\n    return linkData;\n  }\n\n  /**\n   * Updates the given link data based on the new URL results.\n   * Also updates newFailingUrlResults and fixedUrlResults to remember these URLs for the issue comment.\n   *\n   * @returns {LinkData} Updated link data with new statuses for all existing links, new links added and fixed links removed.\n   */\n  function getUpdatedLinkData() {\n    const linkData = {};\n\n    for (const urlResult of urlResults) {\n      const { url, message, failed } = urlResult;\n\n      if (Object.keys(oldLinkData).includes(url)) {\n        // URL is already in table\n\n        const currentStatus = {\n          failed,\n          message,\n          jobUrl: workflowRunUrl,\n        };\n        const oldStatuses = oldLinkData[url];\n\n        const statuses = [currentStatus, ...oldStatuses.slice(0, 6)];\n\n        if (statuses.every((status) => !status.failed)) {\n          // passing for seven days -> don't add to new table but create comment\n          fixedUrlResults.push(urlResult);\n        }\n        else {\n          // still failing -> update table\n          linkData[url] = statuses;\n        }\n      }\n      else if (failed) {\n        // new broken link -> update table and create comment\n\n        const statuses = Array.from(\n          { length: 7 },\n          () => ({\n            failed: false,\n            message: null,\n            jobUrl: null,\n          }),\n        );\n        statuses[0] = {\n          failed,\n          message,\n          jobUrl: workflowRunUrl,\n        };\n        linkData[url] = statuses;\n\n        newFailingUrlResults.push(urlResult);\n      }\n    }\n\n    return linkData;\n  }\n\n  /**\n   * @param {LinkStatus} status The status to get the linked emoji for.\n   * @returns {string} An emoji, wrapped in a link to the failed job if applicable.\n   */\n  function getStatusEmojiLink(status) {\n    if (!status.failed) {\n      return '✔️';\n    }\n\n    const message = status.message.replaceAll('\\n', ' ').replaceAll('\"', '&quot;');\n    const emoji = getFailedEmoji(status.message);\n    return `<a href=\"${status.jobUrl}\" title=\"${message}\">${emoji}</a>`;\n  }\n\n  /**\n   * @param {LinkData} linkData The new link data from which to create the issue body.\n   * @returns {string} The new issue body (in Markdown and HTML) from the given link data.\n   */\n  function getBodyFromLinkData(linkData) {\n    const scriptName = import.meta.url.split('/').slice(-2).join('/');\n    const rows = Object.entries(linkData).map(([url, statuses]) => {\n      const statusIcons = statuses.map((status) => getStatusEmojiLink(status)).join('&nbsp;');\n      const link = `<a href=\"${url}\" target=\"_blank\">${url}</a>`;\n      return `<tr><td nowrap>${statusIcons}</td><td>${link}</td></tr>`;\n    });\n    const lines = [\n      `*Auto-generated content by \\`${scriptName}\\`.*`,\n      '',\n      `**Last updated:** ${new Date().toISOString()}`,\n      '',\n      '<table>',\n      '<tr><th nowrap>today … 6 days ago</th><th>URL</th></tr>',\n      ...rows,\n      '</table>',\n    ];\n    return lines.join('\\n');\n  }\n\n  /**\n   * Deletes all auto-generated issue comments, i.e. comment that were created by this script type earlier, to keep the issue clean.\n   *\n   * @returns {Promise} Promise that resolves as soon as all (or none) comments have been deleted.\n   */\n  async function deleteAutoGeneratedComments() {\n    const { data: comments } = await githubClient.rest.issues.listComments({\n      owner: repoOwner,\n      repo: repoName,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      issue_number: process.env.GITHUB_BROKEN_LINKS_ISSUE_NUMBER,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      per_page: 100,\n    });\n\n    const autoGeneratedComments = comments.filter(\n      (comment) => comment.body.startsWith(GITHUB_COMMENT_HEADING),\n    );\n\n    console.log(`Deleting ${autoGeneratedComments.length} auto-generated GitHub comment(s).`);\n    await Promise.all(autoGeneratedComments.map(\n      (comment) => githubClient.rest.issues.deleteComment({\n        owner: repoOwner,\n        repo: repoName,\n        // eslint-disable-next-line camelcase -- required by GitHub API\n        comment_id: comment.id,\n      }),\n    ));\n  }\n\n  /**\n   * Creates a notifying issue comment if there are new failing or fixed URLs.\n   *\n   * @returns {Promise} Promise that resolves as soon as the comment (or no comment) has been created.\n   */\n  async function createCommentIfNeeded() {\n    if (newFailingUrlResults.length === 0 && fixedUrlResults.length === 0 && deletedUrls.length === 0) {\n      return;\n    }\n\n    const lines = [\n      `${GITHUB_COMMENT_HEADING} (${new Date().toISOString()})`,\n      '',\n      `[📃 Workflow run](${workflowRunUrl})`,\n      '',\n    ];\n\n    if (newFailingUrlResults.length > 0) {\n      lines.push(\n        '### ❌ New failing URLs',\n        ...newFailingUrlResults.map((urlResult) => `- ${urlResult.url} (${urlResult.message})`),\n        '',\n      );\n    }\n\n    if (fixedUrlResults.length > 0) {\n      lines.push(\n        '### ✔️ Fixed URLs (no fails in the last seven days)',\n        ...fixedUrlResults.map((urlResult) => `- ${urlResult.url} (${urlResult.message})`),\n        '',\n      );\n    }\n\n    if (deletedUrls.length > 0) {\n      lines.push(\n        '### ✔️ Fixed URLs (failing URLs not included anymore)',\n        ...deletedUrls.map((url) => `- ${url}`),\n        '',\n      );\n    }\n\n    console.log('Creating GitHub comment.');\n    await githubClient.rest.issues.createComment({\n      owner: repoOwner,\n      repo: repoName,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      issue_number: process.env.GITHUB_BROKEN_LINKS_ISSUE_NUMBER,\n      body: lines.join('\\n'),\n    });\n  }\n}\n\n/**\n * @param {string} message The error message.\n * @returns {string} The emoji to display for that error message.\n */\nfunction getFailedEmoji(message) {\n  switch (message.trim().toLowerCase()) {\n    case '301':\n    case '301 moved permanently': {\n      return '⏩';\n    }\n    case '403':\n    case '403 forbidden': {\n      return '⛔';\n    }\n    case '429':\n    case '429 too many requests': {\n      return '🆘';\n    }\n    case 'certificate has expired':\n    case 'unable to verify the first certificate': {\n      return '🔒';\n    }\n    case `timeout of ${TIMEOUT}ms exceeded.`: {\n      return '⌛';\n    }\n    default: {\n      return '❌';\n    }\n  }\n}\n"
  },
  {
    "path": "tests/fixture-valid.js",
    "content": "import { inspect } from 'util';\nimport getAjvValidator from '../lib/ajv-validator.js';\nimport getAjvErrorMessages from '../lib/get-ajv-error-messages.js';\nimport importJson from '../lib/import-json.js';\nimport FineChannel from '../lib/model/FineChannel.js';\nimport Fixture from '../lib/model/Fixture.js';\nimport NullChannel from '../lib/model/NullChannel.js';\nimport SwitchingChannel from '../lib/model/SwitchingChannel.js';\nimport { getResourceFromString, manufacturerFromRepository } from '../lib/model.js';\nimport { schemaDefinitions } from '../lib/schema-properties.js';\n/** @import AbstractChannel from '../lib/model/AbstractChannel.js' */\n/** @import Capability from '../lib/model/Capability.js' */\n/** @import CoarseChannel from '../lib/model/CoarseChannel.js' */\n/** @import Matrix from '../lib/model/Matrix.js' */\n/** @import Meta from '../lib/model/Meta.js' */\n/** @import Physical from '../lib/model/Physical.js' */\n/** @import TemplateChannel from '../lib/model/TemplateChannel.js' */\n/** @import Wheel from '../lib/model/Wheel.js' */\n\nlet initialized = false;\nlet register;\nlet plugins;\n\n/**\n * Checks that a given fixture JSON object is valid.\n * @param {string} manufacturerKey The manufacturer key.\n * @param {string} fixtureKey The fixture key.\n * @param {object | null} fixtureJson The fixture JSON object.\n * @param {UniqueValues | null} [uniqueValues=null] Values that have to be unique are checked and all new occurrences are appended.\n * @returns {Promise<ResultData>} A Promise that resolves to the result object containing errors and warnings, if any.\n */\nexport async function checkFixture(manufacturerKey, fixtureKey, fixtureJson, uniqueValues = null) {\n  if (!initialized) {\n    register = await importJson('../fixtures/register.json', import.meta.url);\n    plugins = await importJson('../plugins/plugins.json', import.meta.url);\n\n    initialized = true;\n  }\n\n  /**\n   * @typedef {object} ResultData\n   * @property {string[]} errors All errors of this fixture.\n   * @property {string[]} warnings All warnings of this fixture.\n   */\n\n  /** @type {ResultData} */\n  const result = {\n    errors: [],\n    warnings: [],\n  };\n\n  /** @type {Fixture} */\n  let fixture;\n\n  /** @type {Set<string>} */\n  const definedChannelKeys = new Set(); // and aliases\n  /** @type {Set<string>} */\n  const usedChannelKeys = new Set(); // and aliases\n  /** @type {Set<string>} */\n  const allPossibleMatrixChannelKeys = new Set(); // and aliases\n  /** @type {Set<string>} */\n  const usedWheels = new Set();\n  /** @type {Set<string>} */\n  const usedWheelSlots = new Set();\n\n  /** @type {Set<string>} */\n  const modeNames = new Set();\n  /** @type {Set<string>} */\n  const modeShortNames = new Set();\n\n  if (!('$schema' in fixtureJson)) {\n    result.errors.push(getErrorString('File does not contain \\'$schema\\' property.'));\n    return result;\n  }\n\n  if (fixtureJson.$schema.endsWith('/fixture-redirect.json')) {\n    await checkFixtureRedirect();\n    return result;\n  }\n\n  const schemaValidate = await getAjvValidator('fixture');\n  const schemaValid = schemaValidate(fixtureJson);\n  if (!schemaValid) {\n    const errorMessages = getAjvErrorMessages(schemaValidate.errors, 'fixture');\n    result.errors.push(...errorMessages.map((message) => getErrorString('File does not match schema:', message)));\n    return result;\n  }\n\n  try {\n    const manufacturer = await manufacturerFromRepository(manufacturerKey);\n    fixture = new Fixture(manufacturer, fixtureKey, fixtureJson);\n\n    checkFixtureIdentifierUniqueness();\n    checkMeta(fixture.meta);\n    checkLinks();\n    checkPhysical(fixture.physical);\n    checkMatrix(fixture.matrix);\n    await checkWheels(fixture.wheels);\n    checkTemplateChannels();\n    checkChannels();\n\n    for (const mode of fixture.modes) {\n      checkMode(mode);\n    }\n\n    checkUnusedChannels();\n    checkUnusedWheels();\n    checkUnusedWheelSlots();\n    checkCategories();\n    checkRdm();\n  }\n  catch (error) {\n    result.errors.push(getErrorString('File could not be imported into model.', error));\n  }\n\n  return result;\n\n  /**\n   * Checks that a fixture redirect file is valid and redirecting to a fixture correctly.\n   */\n  async function checkFixtureRedirect() {\n    const redirectSchemaValidate = await getAjvValidator('fixture-redirect');\n    const redirectSchemaValid = redirectSchemaValidate(fixtureJson);\n\n    if (!redirectSchemaValid) {\n      result.errors.push(getErrorString('File does not match schema.', redirectSchemaValidate.errors));\n    }\n\n    if (!(fixtureJson.redirectTo in register.filesystem) || 'redirectTo' in register.filesystem[fixtureJson.redirectTo]) {\n      result.errors.push('\\'redirectTo\\' is not a valid fixture.');\n    }\n\n    result.name = `${manufacturerKey}/${fixtureKey}.json (redirect)`;\n  }\n\n  /**\n   * Checks that fixture key, name and shortName are unique.\n   */\n  function checkFixtureIdentifierUniqueness() {\n    // test is called for a single fixture, e.g. when importing\n    if (uniqueValues === null) {\n      return;\n    }\n\n    // fixture.key\n    if (!(manufacturerKey in uniqueValues.fixKeysInMan)) {\n      uniqueValues.fixKeysInMan[manufacturerKey] = new Set();\n    }\n    checkUniqueness(\n      uniqueValues.fixKeysInMan[manufacturerKey],\n      fixture.key,\n      result,\n      `Fixture key '${fixture.key}' is not unique in manufacturer ${manufacturerKey} (test is not case-sensitive).`,\n    );\n\n    // fixture.name\n    if (!(manufacturerKey in uniqueValues.fixNamesInMan)) {\n      uniqueValues.fixNamesInMan[manufacturerKey] = new Set();\n    }\n    checkUniqueness(\n      uniqueValues.fixNamesInMan[manufacturerKey],\n      fixture.name,\n      result,\n      `Fixture name '${fixture.name}' is not unique in manufacturer ${manufacturerKey} (test is not case-sensitive).`,\n    );\n\n    // fixture.shortName\n    checkUniqueness(\n      uniqueValues.fixShortNames,\n      fixture.shortName,\n      result,\n      `Fixture shortName '${fixture.shortName}' is not unique (test is not case-sensitive).`,\n    );\n  }\n\n  /**\n   * Check that a fixture's meta block is valid.\n   * @param {Meta} meta The fixture's Meta object.\n   */\n  function checkMeta(meta) {\n    if (meta.lastModifyDate < meta.createDate) {\n      result.errors.push('meta.lastModifyDate is earlier than meta.createDate.');\n    }\n\n    if (meta.importPlugin) {\n      const pluginData = plugins.data[meta.importPlugin];\n      const isImportPlugin = plugins.importPlugins.includes(meta.importPlugin);\n      const isOutdatedImportPlugin = pluginData && plugins.importPlugins.includes(pluginData.newPlugin);\n\n      if (!(isImportPlugin || isOutdatedImportPlugin)) {\n        result.errors.push(`Unknown import plugin ${meta.importPlugin}`);\n      }\n    }\n  }\n\n  /**\n   * Check that URLs in the fixture's links are unique.\n   */\n  function checkLinks() {\n    if (fixture.links === null) {\n      return;\n    }\n\n    const linkTypesPerUrl = {};\n    for (const [linkType, urls] of Object.entries(fixture.links)) {\n      for (const url of urls) {\n        linkTypesPerUrl[url] ??= [];\n        linkTypesPerUrl[url].push(linkType);\n      }\n    }\n\n    for (const [url, linkTypes] of Object.entries(linkTypesPerUrl)) {\n      if (linkTypes.length > 1) {\n        const linkTypesList = linkTypes.join(', ');\n        result.errors.push(`URL '${url}' is used in multiple link types: ${linkTypesList}.`);\n      }\n    }\n  }\n\n  /**\n   * Checks if the given Physical object is valid.\n   * @param {Physical | null} physical A fixture's or a mode's physical data.\n   * @param {string} [modeDescription=''] Optional information in error messages about current mode.\n   */\n  function checkPhysical(physical, modeDescription = '') {\n    if (physical === null) {\n      return;\n    }\n\n    if (physical.lensDegreesMin > physical.lensDegreesMax) {\n      result.errors.push(`physical.lens.degreesMinMax${modeDescription} is an invalid range.`);\n    }\n\n    if (physical.dimensions !== null && physical.DMXconnector !== null) {\n      const hasSmallDimensions = physical.dimensions.some((dimension) => dimension < 30);\n      const dimensionsString = physical.dimensions.join('×');\n\n      if (hasSmallDimensions) {\n        result.errors.push(`physical.dimensions${modeDescription} are too small (${dimensionsString}mm) for a fixture with a ${physical.DMXconnector} DMX connector. Did you accidentally enter the dimensions in centimeters instead of millimeters?`);\n      }\n    }\n\n    if (physical.hasMatrixPixels && fixture.matrix === null) {\n      result.errors.push('physical.matrixPixels is set but fixture.matrix is missing.');\n    }\n    else if (physical.matrixPixelsSpacing !== null) {\n      checkPhysicalMatrixPixelsSpacing(physical.matrixPixelsSpacing);\n    }\n  }\n\n  /**\n   * Checks if the given physical.matrixPixels.spacing array is valid.\n   * @param {number[]} matrixPixelsSpacing The physical.matrixPixels.spacing array to check.\n   */\n  function checkPhysicalMatrixPixelsSpacing(matrixPixelsSpacing) {\n    for (const [index, axis] of ['X', 'Y', 'Z'].entries()) {\n      if (matrixPixelsSpacing[index] !== 0 && !fixture.matrix.definedAxes.includes(axis)) {\n        result.errors.push(`physical.matrixPixels.spacing is nonzero for ${axis} axis, but no pixels are defined in that axis.`);\n      }\n    }\n  }\n\n  /**\n   * Checks if the given Matrix object is valid.\n   * @param {Matrix | null} matrix A fixture's matrix data.\n   */\n  function checkMatrix(matrix) {\n    if (matrix === null) {\n      return;\n    }\n\n    if (matrix.definedAxes.length === 0) {\n      result.errors.push('Matrix may not consist of only a single pixel.');\n      return;\n    }\n\n    const variesInAxisLength = matrix.pixelKeyStructure.some(\n      (rows) => rows.length !== matrix.pixelCountY || rows.some(\n        (columns) => columns.length !== matrix.pixelCountX,\n      ),\n    );\n    if (variesInAxisLength) {\n      result.errors.push('Matrix must not vary in axis length.');\n    }\n\n    if ('pixelGroups' in matrix.jsonObject) {\n      checkPixelGroups();\n    }\n\n    /**\n     * Check if the referenced pixelKeys from the pixelGroups exist and are not referenced more than once.\n     */\n    function checkPixelGroups() {\n      const pixelGroupKeys = Object.keys(matrix.jsonObject.pixelGroups);\n\n      for (const pixelGroupKey of pixelGroupKeys) {\n        const usedMatrixChannels = new Set();\n\n        if (matrix.pixelKeys.includes(pixelGroupKey)) {\n          result.errors.push(`pixelGroupKey '${pixelGroupKey}' is already used as pixelKey. Please choose a different name.`);\n        }\n\n        if (matrix.pixelGroups[pixelGroupKey].length === 0) {\n          // this can only happen through invalid constraints, empty arrays are caught by the schema\n          result.errors.push(`pixelGroup '${pixelGroupKey}' does not contain any pixelKeys. Please relax the pixel key constraints.`);\n        }\n\n        for (const pixelKey of matrix.pixelGroups[pixelGroupKey]) {\n          if (!matrix.pixelKeys.includes(pixelKey)) {\n            result.errors.push(`pixelGroup '${pixelGroupKey}' references unknown pixelKey '${pixelKey}'.`);\n          }\n          if (usedMatrixChannels.has(pixelKey)) {\n            result.errors.push(`pixelGroup '${pixelGroupKey}' can't reference pixelKey '${pixelKey}' more than once.`);\n          }\n          usedMatrixChannels.add(pixelKey);\n        }\n      }\n    }\n  }\n\n  /**\n   * Checks if the fixture's wheels are correct.\n   * @param {Wheel[]} wheels The fixture's Wheel instances.\n   */\n  async function checkWheels(wheels) {\n    for (const wheel of wheels) {\n      if (!/\\b(?:wheel|disk)\\b/i.test(wheel.name)) {\n        result.warnings.push(`Name of wheel '${wheel.name}' does not contain the word 'wheel' or 'disk', which could lead to confusing capability names.`);\n      }\n\n      const expectedAnimationGoboEndSlots = [];\n      const foundAnimationGoboEndSlots = [];\n\n      await Promise.all(wheel.slots.map(async (slot, index) => {\n        if (slot.type === 'AnimationGoboStart') {\n          expectedAnimationGoboEndSlots.push(index + 1);\n        }\n        else if (slot.type === 'AnimationGoboEnd') {\n          foundAnimationGoboEndSlots.push(index);\n        }\n\n        if (typeof slot.resource === 'string') {\n          try {\n            await getResourceFromString(slot.resource);\n          }\n          catch (error) {\n            result.errors.push(error.message);\n          }\n        }\n      }));\n\n      if (!arraysEqual(expectedAnimationGoboEndSlots, foundAnimationGoboEndSlots)) {\n        result.errors.push(`An 'AnimationGoboEnd' slot must be used after an 'AnimationGoboStart' slot in wheel ${wheel.name}. (${expectedAnimationGoboEndSlots}; ${foundAnimationGoboEndSlots})`);\n      }\n    }\n  }\n\n  /**\n   * Check if templateChannels are defined correctly. Does not check the channel data itself.\n   */\n  function checkTemplateChannels() {\n    if (fixtureJson.templateChannels) {\n      for (const templateChannel of fixture.templateChannels) {\n        checkTemplateChannel(templateChannel);\n      }\n    }\n  }\n\n  /**\n   * Check if the templateChannel is defined correctly. Does not check the channel data itself.\n   * @param {TemplateChannel} templateChannel The templateChannel to examine.\n   */\n  function checkTemplateChannel(templateChannel) {\n    checkTemplateVariables(templateChannel.name, ['$pixelKey']);\n\n    for (const templateKey of templateChannel.allTemplateKeys) {\n      checkTemplateVariables(templateKey, ['$pixelKey']);\n\n      const possibleMatrixChannelKeys = templateChannel.possibleMatrixChannelKeys.get(templateKey);\n\n      const templateChannelUsed = fixture.allChannelKeys.some(\n        (channelKey) => possibleMatrixChannelKeys.includes(channelKey),\n      );\n      if (!templateChannelUsed) {\n        result.warnings.push(`Template channel '${templateKey}' is never used.`);\n      }\n\n      for (const channelKey of possibleMatrixChannelKeys) {\n        checkUniqueness(\n          allPossibleMatrixChannelKeys,\n          channelKey,\n          result,\n          `Generated channel key ${channelKey} can be produced by multiple template channels (test is not case-sensitive).`,\n        );\n      }\n    }\n  }\n\n  /**\n   * Check if all channels are defined correctly.\n   */\n  function checkChannels() {\n    for (const channel of fixture.coarseChannels) {\n      if (!(channel instanceof NullChannel)) {\n        // forbid coexistence of channels 'Red' and 'red'\n        checkUniqueness(\n          definedChannelKeys,\n          channel.key,\n          result,\n          `Channel key '${channel.key}' is already defined (maybe in another letter case).`,\n        );\n        checkChannel(channel);\n      }\n    }\n  }\n\n  /**\n   * Check that an available or template channel is valid.\n   * @param {CoarseChannel} channel The channel to test.\n   */\n  function checkChannel(channel) {\n    checkTemplateVariables(channel.key, []);\n\n    if (/\\bfine\\b|\\d+[\\s_-]*bit/i.test(channel.name)) {\n      // channel name contains the word \"fine\" or \"16bit\" / \"8 bit\" / \"32-bit\" / \"24_bit\"\n      result.errors.push(`Channel '${channel.key}' should rather be a fine channel alias of its corresponding coarse channel.`);\n    }\n    checkTemplateVariables(channel.name, []);\n\n    if (channel.type === 'Unknown') {\n      result.errors.push(`Channel '${channel.key}' has an unknown type.`);\n    }\n\n    // Fine channels\n    for (const alias of channel.fineChannelAliases) {\n      checkTemplateVariables(alias, []);\n      checkUniqueness(\n        definedChannelKeys,\n        alias,\n        result,\n        `Fine channel alias '${alias}' in channel '${channel.key}' is already defined (maybe in another letter case).`,\n      );\n    }\n\n    // Switching channels\n    for (const alias of channel.switchingChannelAliases) {\n      checkTemplateVariables(alias, []);\n      checkUniqueness(\n        definedChannelKeys,\n        alias,\n        result,\n        `Switching channel alias '${alias}' in channel '${channel.key}' is already defined (maybe in another letter case).`,\n      );\n    }\n\n    const maxDmxValue = Math.pow(256, channel.dmxValueResolution) - 1;\n\n    checkChannelDmxValues();\n    checkCapabilities();\n\n    /**\n     * Check that DMX values used in the channel are correct.\n     */\n    function checkChannelDmxValues() {\n      if (channel.dmxValueResolution > channel.maxResolution) {\n        result.errors.push(`dmxValueResolution must be less or equal to ${channel.maxResolution * 8}bit in channel '${channel.key}'.`);\n      }\n\n      if (channel.hasDefaultValue && channel.getDefaultValueWithResolution(channel.dmxValueResolution) > maxDmxValue) {\n        result.errors.push(`defaultValue must be less or equal to ${maxDmxValue} in channel '${channel.key}'.`);\n      }\n\n      if (channel.hasHighlightValue && channel.getHighlightValueWithResolution(channel.dmxValueResolution) > maxDmxValue) {\n        result.errors.push(`highlightValue must be less or equal to ${maxDmxValue} in channel '${channel.key}'.`);\n      }\n    }\n\n    /**\n     * Check that the channel's capabilities are valid.\n     */\n    function checkCapabilities() {\n      let dmxRangesInvalid = false;\n\n      if (\n        channel.capabilities.length === 1\n        && channel.capabilities[0].type === 'ShutterStrobe'\n        && fixture.mainCategory !== 'Strobe'\n        && !channel.capabilities[0].helpWanted?.startsWith('At which DMX values is strobe disabled? When is the lamp constantly on/off?')\n      ) {\n        result.errors.push(`Channel '${channel.key}' only has a single ShutterStrobe capability and the fixture is not a Strobe, so it is not clear when strobe is disabled.`);\n      }\n\n      for (let index = 0; index < channel.capabilities.length; index++) {\n        const capability = channel.capabilities[index];\n\n        // if one of the previous capabilities had an invalid range,\n        // it doesn't make sense to check later ranges\n        if (!dmxRangesInvalid) {\n          dmxRangesInvalid = !checkDmxRange(index);\n        }\n\n        // Use JSON dmxRange rather than rawDmxRange, because that one might throw unhelpful errors\n        const rangeString = `${capability.jsonObject.dmxRange[0]}…${capability.jsonObject.dmxRange[1]}`;\n\n        checkCapability(capability, `Capability '${capability.name}' (${rangeString}) in channel '${channel.key}'`);\n      }\n\n      /**\n       * Check that a capability's range is valid.\n       * @param {number} capabilityNumber The number of the capability in the channel, starting with 0.\n       * @returns {boolean} True if the range is valid, false otherwise. The global `result` object is updated then.\n       */\n      function checkDmxRange(capabilityNumber) {\n        const capability = channel.capabilities[capabilityNumber];\n        const [rawDmxStart, rawDmxEnd] = capability.jsonObject.dmxRange;\n        const errorLocationString = `capability '${capability.name}' (${rawDmxStart}…${rawDmxEnd}) in channel '${channel.key}'`;\n\n        return checkDmxRangeWithinBounds()\n          && checkFirstCapabilityRangeStart()\n          && checkRangeValid()\n          && checkRangesAdjacent()\n          && checkLastCapabilityRangeEnd();\n\n        /**\n         * Checks that the capability's DMX range values don't exceed the maximum value for the channel's resolution.\n         * @returns {boolean} True if the DMX range is within bounds, false otherwise.\n         */\n        function checkDmxRangeWithinBounds() {\n          if (rawDmxStart > maxDmxValue || rawDmxEnd > maxDmxValue) {\n            result.errors.push(`dmxRange is out of bounds (maximum ${maxDmxValue} for ${channel.dmxValueResolution * 8}bit resolution) in ${errorLocationString}.`);\n            return false;\n          }\n\n          return true;\n        }\n\n        /**\n         * Checks that the first capability's DMX range starts with 0.\n         * @returns {boolean} True if this is not the first capability or it starts with 0, false otherwise.\n         */\n        function checkFirstCapabilityRangeStart() {\n          if (capabilityNumber === 0 && capability.rawDmxRange.start !== 0) {\n            result.errors.push(`The first dmxRange has to start at 0 in ${errorLocationString}.`);\n            return false;\n          }\n\n          return true;\n        }\n\n        /**\n         * @returns {boolean} True if this capability's DMX range is valid, i.e. the end is greater than or equal to the start, false otherwise.\n         */\n        function checkRangeValid() {\n          if (capability.rawDmxRange.start > capability.rawDmxRange.end) {\n            result.errors.push(`dmxRange invalid in ${errorLocationString}.`);\n            return false;\n          }\n\n          return true;\n        }\n\n        /**\n         * @returns {boolean} True if this capability's DMX range start is adjacent to the previous capability's DMX range end, false otherwise.\n         */\n        function checkRangesAdjacent() {\n          if (capabilityNumber > 0) {\n            const previousCapability = channel.capabilities[capabilityNumber - 1];\n\n            if (capability.rawDmxRange.start !== previousCapability.rawDmxRange.end + 1) {\n              result.errors.push(`dmxRanges must be adjacent in capabilities '${previousCapability.name}' (${previousCapability.rawDmxRange}) and '${capability.name}' (${capability.rawDmxRange}) in channel '${channel.key}'.`);\n              return false;\n            }\n          }\n\n          return true;\n        }\n\n        /**\n         * Checks that the last capability's DMX range is one of the allowed values, e.g. 255 or 65535 for 16bit channels.\n         * @returns {boolean} True if this is not the last capability or it ends with an allowed value, false otherwise.\n         */\n        function checkLastCapabilityRangeEnd() {\n          if (capabilityNumber === channel.capabilities.length - 1 && channel.capabilities[capabilityNumber].rawDmxRange.end !== maxDmxValue) {\n            result.errors.push(`The last dmxRange has to end at ${maxDmxValue} (or another channel.dmxValueResolution must be chosen) in ${errorLocationString}.`);\n            return false;\n          }\n\n          return true;\n        }\n      }\n\n      /**\n       * Check that a capability is valid (except its DMX range).\n       * @param {Capability} capability The capability to check.\n       * @param {string} errorPrefix An identifier for the capability to use in errors and warnings.\n       */\n      function checkCapability(capability, errorPrefix) {\n        const switchingChannelAliases = Object.keys(capability.switchChannels);\n        if (arraysEqual(switchingChannelAliases, channel.switchingChannelAliases)) {\n          for (const alias of switchingChannelAliases) {\n            const channelKey = capability.switchChannels[alias];\n            usedChannelKeys.add(channelKey.toLowerCase());\n\n            if (channel.fixture.getChannelByKey(channelKey) === null) {\n              result.errors.push(`${errorPrefix} references unknown channel '${channelKey}'.`);\n            }\n          }\n        }\n        else {\n          result.errors.push(`${errorPrefix} must define the same switching channel aliases as all other capabilities.`);\n        }\n\n        checkStartEndEntities();\n\n        const capabilityTypeChecks = {\n          ShutterStrobe: checkShutterStrobeCapability,\n          StrobeSpeed: checkStrobeSpeedCapability,\n          Pan: checkPanTiltCapability,\n          Tilt: checkPanTiltCapability,\n          WheelSlot: checkWheelCapability,\n          WheelShake: checkWheelCapability,\n          WheelSlotRotation: checkWheelCapability,\n          WheelRotation: checkWheelCapability,\n          Effect: checkEffectCapability,\n        };\n\n        if (Object.keys(capabilityTypeChecks).includes(capability.type)) {\n          capabilityTypeChecks[capability.type]();\n        }\n\n        /**\n         * Check all used start/end entities in the capability.\n         */\n        function checkStartEndEntities() {\n          for (const property of capability.usedStartEndEntities) {\n            const [startEntity, endEntity] = capability[property];\n\n            if ((startEntity.keyword === null) !== (endEntity.keyword === null)) {\n              result.errors.push(`${errorPrefix} must use keywords for both start and end value or for neither in ${property}.`);\n            }\n            else if (startEntity.unit !== endEntity.unit) {\n              result.errors.push(`${errorPrefix} uses different units for ${property}.`);\n            }\n\n            if (property === 'speed' && startEntity.number * endEntity.number < 0) {\n              result.errors.push(`${errorPrefix} uses different signs (+ or –) in ${property} (maybe behind a keyword). Split it into several capabilities instead.`);\n            }\n\n            if (`${property}Start` in capability.jsonObject && startEntity.equals(endEntity)) {\n              result.errors.push(`${errorPrefix} uses ${property}Start and ${property}End with equal values. Use the single property '${property}: \"${startEntity}\"' instead.`);\n            }\n          }\n        }\n\n        /**\n         * Type-specific checks for ShutterStrobe capabilities.\n         */\n        function checkShutterStrobeCapability() {\n          if (['Closed', 'Open'].includes(capability.shutterEffect)) {\n            if (capability.isSoundControlled) {\n              result.errors.push(`${errorPrefix}: Shutter open/closed can't be sound-controlled.`);\n            }\n\n            if (capability.speed !== null || capability.duration !== null) {\n              result.errors.push(`${errorPrefix}: Shutter open/closed can't define speed or duration.`);\n            }\n\n            if (capability.randomTiming) {\n              result.errors.push(`${errorPrefix}: Shutter open/closed can't have random timing.`);\n            }\n          }\n        }\n\n        /**\n         * Type-specific checks for StrobeSpeed capabilities.\n         */\n        function checkStrobeSpeedCapability() {\n          const otherCapabilityHasShutterStrobe = channel.capabilities.some((otherCapability) => otherCapability.type === 'ShutterStrobe');\n          const hasOtherStrobeChannel = fixture.coarseChannels.some((otherChannel) => otherChannel !== channel && otherChannel.type === 'Strobe');\n          if (otherCapabilityHasShutterStrobe && !hasOtherStrobeChannel) {\n            result.errors.push(`${errorPrefix}: StrobeSpeed can't be used in the same channel as ShutterStrobe. Should this rather be a ShutterStrobe capability with shutterEffect \"Strobe\"?`);\n          }\n        }\n\n        /**\n         * Check that references to wheels are valid.\n         */\n        function checkWheelCapability() {\n          let shouldCheckSlotNumbers = true;\n\n          checkReferencedWheels();\n\n          if (capability.slotNumber !== null && shouldCheckSlotNumbers) {\n            checkSlotNumbers();\n          }\n\n          /**\n           * Check that referenced wheels exist in the fixture.\n           */\n          function checkReferencedWheels() {\n            if ('wheel' in capability.jsonObject) {\n              const wheelNames = [capability.jsonObject.wheel].flat();\n\n              for (const wheelName of wheelNames) {\n                const wheel = fixture.getWheelByName(wheelName);\n                if (wheel) {\n                  usedWheels.add(wheelName);\n                }\n                else {\n                  result.errors.push(`${errorPrefix} references wheel '${wheelName}' which is not defined in the fixture.`);\n                  shouldCheckSlotNumbers = false;\n                }\n              }\n\n              if (wheelNames.length === 1 && wheelNames[0] === capability._channel.name) {\n                result.errors.push(`${errorPrefix} explicitly references wheel '${wheelNames[0]}', which is the default anyway (through the channel name). Please remove the 'wheel' property.`);\n              }\n            }\n            else if (capability.wheels.includes(null)) {\n              result.errors.push(`${errorPrefix} does not explicitly reference any wheel, but the default wheel '${capability._channel.name}' (through the channel name) does not exist.`);\n              shouldCheckSlotNumbers = false;\n            }\n            else {\n              usedWheels.add(capability._channel.name);\n            }\n          }\n\n          /**\n           * Check that slot indices are used correctly for the specific wheel.\n           */\n          function checkSlotNumbers() {\n            const min = Math.min(capability.slotNumber[0], capability.slotNumber[1]);\n            const max = Math.max(capability.slotNumber[0], capability.slotNumber[1]);\n            for (let index = Math.floor(min); index <= Math.ceil(max); index++) {\n              usedWheelSlots.add(`${capability.wheels[0].name} (slot ${index})`);\n            }\n\n            if (max - min > 1 && !capability.helpWanted?.endsWith('can be selected at which DMX values?')) {\n              result.errors.push(`${errorPrefix} references a wheel slot range (${min}…${max}) which is greater than 1.`);\n            }\n\n            const minSlotNumber = 1;\n            const maxSlotNumber = capability.wheels[0].slots.length;\n\n            const isInRangeExclusive = (number, start, end) => number > start && number < end;\n            const isInRangeInclusive = (number, start, end) => number >= start && number <= end;\n\n            if (capability.slotNumber[0].equals(capability.slotNumber[1])) {\n              if (!isInRangeExclusive(capability.slotNumber[0].number, minSlotNumber - 1, maxSlotNumber + 1)) {\n                result.errors.push(`${errorPrefix} references wheel slot ${capability.slotNumber[0].number} which is outside the allowed range ${minSlotNumber - 1}…${maxSlotNumber + 1} (exclusive).`);\n              }\n              return;\n            }\n\n            if (!isInRangeInclusive(capability.slotNumber[0].number, minSlotNumber - 1, maxSlotNumber)) {\n              result.errors.push(`${errorPrefix} starts at wheel slot ${capability.slotNumber[0].number} which is outside the allowed range ${minSlotNumber - 1}…${maxSlotNumber} (inclusive).`);\n            }\n            else if (!isInRangeInclusive(capability.slotNumber[1].number, minSlotNumber, maxSlotNumber + 1)) {\n              result.errors.push(`${errorPrefix} ends at wheel slot ${capability.slotNumber[1].number} which is outside the allowed range ${minSlotNumber}…${maxSlotNumber + 1} (inclusive).`);\n            }\n          }\n        }\n\n        /**\n         * Type-specific checks for Pan and Tilt capabilities.\n         */\n        function checkPanTiltCapability() {\n          const usesPercentageAngle = capability.angle[0].unit === '%';\n          if (usesPercentageAngle && capability.helpWanted !== 'Can you provide exact angles?') {\n            result.errors.push(`${errorPrefix} defines an imprecise percentaged angle. Please try to find the value in degrees.`);\n          }\n        }\n\n        /**\n         * Type-specific checks for Effect capabilities.\n         */\n        function checkEffectCapability() {\n          if (capability.effectPreset === null && schemaDefinitions.effectPreset.enum.includes(capability.effectName)) {\n            result.errors.push(`${errorPrefix} must use effectPreset instead of effectName with '${capability.effectName}'.`);\n          }\n\n          if (!capability.isSoundControlled && capability.soundSensitivity !== null) {\n            result.errors.push(`${errorPrefix} can't set soundSensitivity if soundControlled is not true.`);\n          }\n        }\n      }\n    }\n  }\n\n  /**\n   * Check that a mode is valid.\n   * @param {Mode} mode The mode to check.\n   */\n  function checkMode(mode) {\n    checkUniqueness(\n      modeNames,\n      mode.name,\n      result,\n      `Mode name '${mode.name}' is not unique (test is not case-sensitive).`,\n    );\n    checkUniqueness(\n      modeShortNames,\n      mode.shortName,\n      result,\n      `Mode shortName '${mode.shortName}' is not unique (test is not case-sensitive).`,\n    );\n\n    checkModeName();\n\n    checkPhysical(mode.physicalOverride, ` in mode '${mode.shortName}'`);\n\n    for (const rawReference of mode.jsonObject.channels) {\n      if (rawReference !== null && typeof rawReference !== 'string') {\n        checkChannelInsertBlock(rawReference);\n      }\n    }\n\n    for (let channelIndex = 0; channelIndex < mode.channelKeys.length; channelIndex++) {\n      checkModeChannelKey(channelIndex);\n    }\n\n    /**\n     * Check that mode names comply with the channel count.\n     */\n    function checkModeName() {\n      // \"6ch\" / \"8-Channel\" / \"9 channels\" mode names\n      for (const nameProperty of ['name', 'shortName']) {\n        const match = mode[nameProperty].match(/(\\d+)(?:\\s+|-|)(?:channels?|ch)/i);\n        if (match !== null) {\n          const intendedLength = Number.parseInt(match[1], 10);\n\n          if (mode.channels.length !== intendedLength) {\n            result.errors.push(`Mode '${mode.name}' should have ${intendedLength} channels according to its ${nameProperty} but actually has ${mode.channels.length}.`);\n          }\n\n          const allowedShortNames = [`${intendedLength}ch`, `Ch${intendedLength}`, `Ch0${intendedLength}`];\n          if (mode[nameProperty].length === match[0].length && !allowedShortNames.includes(mode.shortName)) {\n            result.warnings.push(`Mode '${mode.name}' should have shortName '${intendedLength}ch' instead of '${mode.shortName}'.`);\n          }\n        }\n      }\n    }\n\n    /**\n     * Checks if the given complex channel insert block is valid.\n     * @param {object} insertBlock The raw JSON data of the insert block.\n     */\n    function checkChannelInsertBlock(insertBlock) {\n      if (insertBlock.insert === 'matrixChannels') {\n        checkMatrixInsertBlock(insertBlock);\n      }\n      // open for future extensions (invalid values are prohibited by the schema)\n\n      /**\n       * Checks the given matrix channel insert.\n       * @param {object} matrixInsertBlock The matrix channel reference specified in the mode's json channel list.\n       * @param {'matrixChannels'} matrixInsertBlock.insert Indicates that this is a matrix insert.\n       * @param {'eachPixel' | 'eachPixelGroup' | string[]} matrixInsertBlock.repeatFor The pixelKeys or pixelGroupKeys for which the specified channels should be repeated.\n       * @param {'perPixel' | 'perChannel'} matrixInsertBlock.channelOrder Order the channels like RGB1/RGB2/RGB3 or R123/G123/B123.\n       * @param {(string | null)[]} matrixInsertBlock.templateChannels The template channel keys (and aliases) or null channels to be repeated.\n       */\n      function checkMatrixInsertBlock(matrixInsertBlock) {\n        checkMatrixInsertBlockRepeatFor();\n\n        for (const templateKey of matrixInsertBlock.templateChannels) {\n          const templateChannelExists = fixture.templateChannels.some((channel) => channel.allTemplateKeys.includes(templateKey));\n          if (!templateChannelExists) {\n            result.errors.push(`Template channel '${templateKey}' doesn't exist.`);\n          }\n        }\n\n        /**\n         * Checks the used pixel (group) keys for existence and duplicates. Also respects pixel keys included in a pixel group.\n         */\n        function checkMatrixInsertBlockRepeatFor() {\n          if (typeof matrixInsertBlock.repeatFor === 'string') {\n            // no custom pixel key list, keywords are already tested by schema\n            return;\n          }\n\n          for (const pixelKey of matrixInsertBlock.repeatFor) {\n            if (!fixture.matrix.pixelKeys.includes(pixelKey) && !(pixelKey in fixture.matrix.pixelGroups)) {\n              result.errors.push(`Unknown pixelKey or pixelGroupKey '${pixelKey}'`);\n            }\n          }\n        }\n      }\n    }\n\n    /**\n     * Check that a channel reference in a mode is valid.\n     * @param {number} channelIndex The mode's channel index.\n     */\n    function checkModeChannelKey(channelIndex) {\n      const channelKey = mode.channelKeys[channelIndex];\n\n      if (channelKey === null) {\n        return;\n      }\n\n      usedChannelKeys.add(channelKey.toLowerCase());\n\n      const channel = mode.fixture.getChannelByKey(channelKey);\n      if (channel === null) {\n        result.errors.push(`Channel '${channelKey}' is referenced from mode '${mode.shortName}' but is not defined.`);\n        return;\n      }\n\n      // if earliest occurrence (including switching channels) is not this one\n      if (mode.getChannelIndex(channel.key, 'all') < channelIndex) {\n        result.errors.push(`Channel '${channel.key}' is referenced more than once from mode '${mode.shortName}' (maybe through switching channels).`);\n      }\n\n      if (channel instanceof SwitchingChannel) {\n        checkSwitchingChannelReference();\n      }\n      else if (channel instanceof FineChannel) {\n        checkCoarserChannelsInMode(channel);\n      }\n\n      /**\n       * Check that a switching channel reference in a mode is valid.\n       */\n      function checkSwitchingChannelReference() {\n        // the mode must also contain the trigger channel\n        if (mode.getChannelIndex(channel.triggerChannel.key) === -1) {\n          result.errors.push(`mode '${mode.shortName}' uses switching channel '${channel.key}' but is missing its trigger channel '${channel.triggerChannel.key}'`);\n        }\n\n        for (const switchToChannel of channel.switchToChannels) {\n          if (switchToChannel === null) {\n            // channel doesn't exist, but we already added an error when the switching channel was defined\n            continue;\n          }\n\n          // if the channel can be switched to a fine channel, the mode must also contain coarser channels\n          if (switchToChannel instanceof FineChannel) {\n            checkCoarserChannelsInMode(switchToChannel);\n          }\n        }\n\n        for (let index = 0; index < mode.getChannelIndex(channel.key); index++) {\n          const otherChannel = mode.channels[index];\n          checkSwitchingChannelReferenceDuplicate(otherChannel);\n        }\n\n        /**\n         * Check all switched channels in the switching channels against another channel\n         * for duplicate channel usage (either directly or in another switching channel).\n         * @param {AbstractChannel} otherChannel The channel that should be checked against.\n         */\n        function checkSwitchingChannelReferenceDuplicate(otherChannel) {\n          if (channel.switchToChannels.includes(otherChannel)) {\n            result.errors.push(`Channel '${otherChannel.key}' is referenced more than once from mode '${mode.shortName}' through switching channel '${channel.key}'.`);\n            return;\n          }\n\n          if (!(otherChannel instanceof SwitchingChannel)) {\n            return;\n          }\n\n          if (otherChannel.triggerChannel === channel.triggerChannel) {\n            // compare ranges\n            for (const switchToChannelKey of channel.switchToChannelKeys) {\n              const overlap = channel.triggerRanges[switchToChannelKey].some(\n                // `?? []` because otherChannel.switchToChannelKeys may not include switchToChannelKey\n                (range) => range.overlapsWithOneOf(otherChannel.triggerRanges[switchToChannelKey] ?? []),\n              );\n              if (overlap) {\n                result.errors.push(`Channel '${switchToChannelKey}' is referenced more than once from mode '${mode.shortName}' through switching channels '${otherChannel.key}' and ${channel.key}'.`);\n              }\n            }\n          }\n          else {\n            // fail if one of this channel's switchToChannels appears anywhere\n            const firstDuplicate = channel.switchToChannels.find(\n              (switchToChannel) => otherChannel.usesChannelKey(switchToChannel.key, 'all'),\n            );\n            if (firstDuplicate !== undefined) {\n              result.errors.push(`Channel '${firstDuplicate.key}' is referenced more than once from mode '${mode.shortName}' through switching channels '${otherChannel.key}' and ${channel.key}'.`);\n            }\n          }\n        }\n      }\n\n      /**\n       * Check that all coarser channels of the given fine channel are present in the current mode.\n       * @param {FineChannel} fineChannel The fine channel to check.\n       */\n      function checkCoarserChannelsInMode(fineChannel) {\n        const coarseChannel = fineChannel.coarseChannel;\n        const coarserChannelKeys = [...coarseChannel.fineChannelAliases.filter(\n          (alias, index) => index < fineChannel.resolution - 2,\n        ), coarseChannel.key];\n\n        const notInMode = coarserChannelKeys.filter(\n          (coarseChannelKey) => mode.getChannelIndex(coarseChannelKey) === -1,\n        );\n\n        if (notInMode.length > 0) {\n          result.errors.push(`Mode '${mode.shortName}' contains the fine channel '${fineChannel.key}' but is missing its coarser channels ${notInMode}.`);\n        }\n      }\n    }\n  }\n\n  /**\n   * Add a warning if there are unused channels.\n   */\n  function checkUnusedChannels() {\n    const unused = [...definedChannelKeys].filter(\n      (channelKey) => !usedChannelKeys.has(channelKey),\n    ).join(', ');\n\n    if (unused.length > 0) {\n      result.warnings.push(`Unused channel(s): ${unused}`);\n    }\n  }\n\n  /**\n   * Add a warning if there are unused wheels.\n   */\n  function checkUnusedWheels() {\n    const unusedWheels = fixture.wheels.filter(\n      (wheel) => !usedWheels.has(wheel.name),\n    ).map((wheel) => wheel.name).join(', ');\n\n    if (unusedWheels.length > 0) {\n      result.warnings.push(`Unused wheel(s): ${unusedWheels}`);\n    }\n  }\n\n  /**\n   * Add a warning if there are unused wheel slots.\n   */\n  function checkUnusedWheelSlots() {\n    const slotsOfUsedWheels = [];\n    for (const wheelName of usedWheels) {\n      const wheel = fixture.getWheelByName(wheelName);\n\n      if (wheel.type !== 'AnimationGobo') {\n        slotsOfUsedWheels.push(...(wheel.slots.map(\n          (slot, slotIndex) => `${wheelName} (slot ${slotIndex + 1})`,\n        )));\n      }\n    }\n\n    const unusedWheelSlots = slotsOfUsedWheels.filter(\n      (slot) => !usedWheelSlots.has(slot),\n    ).join(', ');\n\n    if (unusedWheelSlots.length > 0) {\n      result.warnings.push(`Unused wheel slot(s): ${unusedWheelSlots}`);\n    }\n  }\n\n  /**\n   * Checks if the used channels fits to the fixture's categories and raise warnings suggesting to add/remove a category.\n   */\n  function checkCategories() {\n    const mutuallyExclusiveGroups = [\n      ['Moving Head', 'Scanner', 'Barrel Scanner'],\n      ['Pixel Bar', 'Flower'],\n      ['Pixel Bar', 'Stand'],\n    ];\n\n    const fixtureIsColorChanger = isColorChanger();\n    const fixtureHasBothPanTiltChannels = hasPanTiltChannels(true);\n    const fixtureHasPanOrTiltChannels = hasPanTiltChannels(false);\n    const isFogTypeFog = isFogType('Fog');\n    const isFogTypeHaze = isFogType('Haze');\n    const fixtureIsNotMatrix = isNotMatrix();\n    const fixtureIsPixelBar = isPixelBar();\n    const fixtureIsNotPixelBar = isNotPixelBar();\n\n    const categories = {\n      'Color Changer': {\n        isSuggested: fixtureIsColorChanger,\n        isInvalid: !fixtureIsColorChanger,\n        suggestedPhrase: 'there are ColorPreset or ColorIntensity capabilities or Color wheel slots',\n        invalidPhrase: 'there are no ColorPreset and less than two ColorIntensity capabilities and no Color wheel slots',\n      },\n      'Moving Head': {\n        isSuggested: fixtureHasBothPanTiltChannels,\n        isInvalid: !fixtureHasBothPanTiltChannels,\n        suggestedPhrase: 'there are pan and tilt channels',\n        invalidPhrase: 'there are not both pan and tilt channels',\n      },\n      'Scanner': {\n        isSuggested: fixtureHasBothPanTiltChannels,\n        isInvalid: !fixtureHasPanOrTiltChannels,\n        suggestedPhrase: 'there are pan and tilt channels',\n        invalidPhrase: 'there are no pan or tilt channels',\n      },\n      'Barrel Scanner': {\n        isSuggested: fixtureHasBothPanTiltChannels,\n        isInvalid: !fixtureHasPanOrTiltChannels,\n        suggestedPhrase: 'there are pan and tilt channels',\n        invalidPhrase: 'there are no pan or tilt channels',\n      },\n      'Smoke': {\n        isSuggested: isFogTypeFog,\n        isInvalid: !isFogTypeFog,\n        suggestedPhrase: 'there are Fog/FogType capabilities with no fogType or fogType \\'Fog\\'',\n        invalidPhrase: 'there are no Fog/FogType capabilities or none has fogType \\'Fog\\'',\n      },\n      'Hazer': {\n        isSuggested: isFogTypeHaze,\n        isInvalid: !isFogTypeHaze,\n        suggestedPhrase: 'there are Fog/FogType capabilities with no fogType or fogType \\'Haze\\'',\n        invalidPhrase: 'there are no Fog/FogType capabilities or none has fogType \\'Haze\\'',\n      },\n      'Matrix': {\n        isInvalid: fixtureIsNotMatrix,\n        invalidPhrase: 'fixture does not define a matrix',\n      },\n      'Pixel Bar': {\n        isSuggested: fixtureIsPixelBar,\n        isInvalid: fixtureIsNotPixelBar,\n        suggestedPhrase: 'matrix pixels are horizontally aligned',\n        invalidPhrase: 'no horizontally aligned matrix is defined',\n      },\n    };\n\n    for (const [categoryName, categoryProperties] of Object.entries(categories)) {\n      const isCategoryUsed = fixture.categories.includes(categoryName);\n\n      // don't suggest this category if another mutually exclusive category is used\n      const exclusiveGroups = mutuallyExclusiveGroups.filter(\n        (group) => group.includes(categoryName) && group.some(\n          (category) => category !== categoryName && fixture.categories.includes(category),\n        ),\n      );\n\n      if (!isCategoryUsed) {\n        if (categoryProperties.isSuggested && exclusiveGroups.length === 0) {\n          result.warnings.push(`Category '${categoryName}' suggested since ${categoryProperties.suggestedPhrase}.`);\n        }\n      }\n      else if (categoryProperties.isInvalid) {\n        result.errors.push(`Category '${categoryName}' invalid since ${categoryProperties.invalidPhrase}.`);\n      }\n      else if (exclusiveGroups.length > 0) {\n        result.errors.push(...exclusiveGroups.map((group) => {\n          const usedCategories = group\n            .filter((category) => fixture.categories.includes(category))\n            .map((category) => `'${category}'`)\n            .join(', ');\n          return `Categories ${usedCategories} can't be used together.`;\n        }));\n      }\n    }\n\n    /**\n     * @returns {boolean} Whether the 'Color Changer' category is suggested.\n     */\n    function isColorChanger() {\n      return (\n        hasCapabilityOfType('ColorPreset')\n        || hasMultipleColorIntensityCapabilities()\n        || fixture.wheels.some(\n          (wheel) => wheel.slots.some((slot) => slot.type === 'Color'),\n        )\n      );\n    }\n\n    /**\n     * @returns {boolean} Whether the fixture has multiple ColorIntensity capabilities (excluding UV, Cold White, and Warm White).\n     */\n    function hasMultipleColorIntensityCapabilities() {\n      return fixture.capabilities.filter(\n        (capability) =>\n          capability.type === 'ColorIntensity'\n          && capability.color !== 'UV'\n          && capability.color !== 'Cold White'\n          && capability.color !== 'Warm White',\n      ).length >= 2;\n    }\n\n    /**\n     * @param {boolean} [both=false] Whether there need to be both Pan and Tilt channels.\n     * @returns {boolean} Whether the fixture has a Pan(Continuous) and/or (depending on 'both') a Tilt(Continuous) channel.\n     */\n    function hasPanTiltChannels(both = false) {\n      const hasPan = hasCapabilityOfType('Pan') || hasCapabilityOfType('PanContinuous');\n      const hasTilt = hasCapabilityOfType('Tilt') || hasCapabilityOfType('TiltContinuous');\n      return both ? (hasPan && hasTilt) : (hasPan || hasTilt);\n    }\n\n    /**\n     * @param {string} type What capability type to search for.\n     * @param {number} [minimum=1] How many occurrences are needed to succeed.\n     * @returns {boolean} Whether the given capability type occurs at least at the given minimum times in the fixture.\n     */\n    function hasCapabilityOfType(type, minimum = 1) {\n      return fixture.capabilities.filter(\n        (capability) => capability.type === type,\n      ).length >= minimum;\n    }\n\n    /**\n     * @param {string} fogType The fog type to search for.\n     * @returns {boolean} Whether the fixture has the given fog type.\n     */\n    function isFogType(fogType) {\n      const fogCapabilities = fixture.capabilities.filter(\n        (capability) => capability.type.startsWith('Fog'),\n      );\n\n      if (fogCapabilities.length === 0) {\n        return false;\n      }\n\n      return fogCapabilities.some((capability) => capability.fogType === fogType) || fogCapabilities.every((capability) => capability.fogType === null);\n    }\n\n    /**\n     * @returns {boolean} True if it can't be a matrix.\n     */\n    function isNotMatrix() {\n      return fixture.matrix === null || fixture.matrix.definedAxes.length < 2;\n    }\n\n    /**\n     * @returns {boolean} True if a matrix with only one axis, which has more than 4 pixels, is defined.\n     */\n    function isPixelBar() {\n      if (fixture.matrix === null) {\n        return false;\n      }\n\n      const definedAxes = fixture.matrix.definedAxes;\n      const definedAxis = definedAxes[0];\n\n      return definedAxes.length === 1 && fixture.matrix[`pixelCount${definedAxis}`] > 4;\n    }\n\n    /**\n     * @returns {boolean} True if it can't be a pixel bar.\n     */\n    function isNotPixelBar() {\n      return fixture.matrix === null || fixture.matrix.definedAxes.length > 1;\n    }\n  }\n\n  /**\n   * Checks if everything regarding this fixture's RDM data is correct.\n   */\n  function checkRdm() {\n    if (fixture.rdm === null || uniqueValues === null) {\n      return;\n    }\n\n    // fixture.rdm.modelId must be unique per manufacturer\n    if (!(manufacturerKey in uniqueValues.fixRdmIdsInMan)) {\n      uniqueValues.fixRdmIdsInMan[manufacturerKey] = new Set();\n    }\n    checkUniqueness(\n      uniqueValues.fixRdmIdsInMan[manufacturerKey],\n      `${fixture.rdm.modelId}`,\n      result,\n      `Fixture RDM model ID '${fixture.rdm.modelId}' is not unique in manufacturer ${manufacturerKey}.`,\n    );\n\n    if (fixture.manufacturer.rdmId === null) {\n      result.errors.push(`Fixture has RDM data, but manufacturer '${fixture.manufacturer.name}' has not.`);\n    }\n\n    const rdmPersonalityIndices = new Set();\n    for (const mode of fixture.modes) {\n      if (mode.rdmPersonalityIndex !== null) {\n        checkUniqueness(\n          rdmPersonalityIndices,\n          `${mode.rdmPersonalityIndex}`,\n          result,\n          `RDM personality index '${mode.rdmPersonalityIndex}' in mode '${mode.shortName}' is not unique in the fixture.`,\n        );\n      }\n    }\n  }\n\n  /**\n   * Checks whether the specified string contains all allowed and no disallowed variables and pushes an error on wrong variable usage.\n   * @param {string} string The string to be checked.\n   * @param {string[]} allowedVariables Variables that must be included in the string; all other variables are forbidden. Specify them with leading dollar sign ($var).\n   */\n  function checkTemplateVariables(string, allowedVariables) {\n    const usedVariables = string.match(/\\$\\w+/g) || [];\n    for (const usedVariable of usedVariables) {\n      if (!allowedVariables.includes(usedVariable)) {\n        result.errors.push(`Variable ${usedVariable} not allowed in '${string}'`);\n      }\n    }\n    for (const allowedVariable of allowedVariables) {\n      if (!usedVariables.includes(allowedVariable)) {\n        result.errors.push(`Variable ${allowedVariable} missing in '${string}'`);\n      }\n    }\n  }\n}\n\n/**\n * If the Set already contains the given value, add an error. Test is not case-sensitive.\n * @param {Set<string>} set The Set in which all unique values are stored.\n * @param {string} value The string value to examine.\n * @param {ResultData} result The object to add the error message to (if any).\n * @param {string} messageIfNotUnique If the value is not unique, add this message to errors.\n */\nexport function checkUniqueness(set, value, result, messageIfNotUnique) {\n  if (set.has(value.toLowerCase())) {\n    result.errors.push(messageIfNotUnique);\n  }\n  set.add(value.toLowerCase());\n}\n\n/**\n * @param {string} description The error message.\n * @param {unknown} error An error object to append to the message.\n * @returns {string} A string containing the message and a deep inspection of the given error object.\n */\nfunction getErrorString(description, error) {\n  if (typeof error === 'string') {\n    return `${description} ${error}`;\n  }\n\n  return `${description} ${inspect(error, false, null)}`;\n}\n\n/**\n * @param {Array | null} a An array.\n * @param {Array | null} b Another array.\n * @returns {boolean} True if both arrays are equal, false if they are null or not equal.\n */\nfunction arraysEqual(a, b) {\n  if (a === b) {\n    return true;\n  }\n\n  if (a == null || b == null || a.length !== b.length) {\n    return false;\n  }\n\n  return a.every((value, index) => value === b[index]);\n}\n"
  },
  {
    "path": "tests/fixtures-valid.js",
    "content": "#!/usr/bin/env node\n\nimport { readdir } from 'fs/promises';\nimport path from 'path';\nimport { styleText } from 'util';\nimport minimist from 'minimist';\nimport getAjvValidator from '../lib/ajv-validator.js';\nimport getAjvErrorMessages from '../lib/get-ajv-error-messages.js';\nimport importJson from '../lib/import-json.js';\nimport { checkFixture, checkUniqueness } from './fixture-valid.js';\n\nconst cliArguments = minimist(process.argv.slice(2), {\n  boolean: ['h', 'a'],\n  alias: { h: 'help', a: 'all-fixtures' },\n});\n\nconst scriptName = import.meta.url.split('/').pop();\n\nconst helpMessage = [\n  'Check validity of some/all fixtures',\n  `Usage: node ${scriptName} -a | -h | fixtures [...]`,\n  'Options:',\n  '  fixtures: a list of fixtures contained in the fixtures/ directory.',\n  '     has to resolve to the form \\'manufacturer/fixture\\'',\n  '     depending on your shell, you can use glob-patterns to match multiple fixtures',\n  '  --all-fixtures, -a:',\n  '     check all fixtures contained in the fixtures/ directory',\n  '  --help, -h:',\n  '     Show this help message.',\n].join('\\n');\n\nlet fixturePaths = cliArguments._;\n\n// print help and exit on -h or no fixtures given.\nif (cliArguments.help || (fixturePaths.length === 0 && !cliArguments.a)) {\n  console.log(helpMessage);\n  process.exit(0);\n}\n\n/**\n * @typedef {object} UniqueValues\n * @property {Set<string>} manNames All manufacturer names\n * @property {Record<string, Set<string>>} fixKeysInMan All fixture keys by manufacturer key\n * @property {Record<string, Set<string>>} fixNamesInMan All fixture names by manufacturer key\n * @property {Record<string, Set<string>>} fixRdmIdsInMan All RDM ids by manufacturer key\n * @property {Set<string>} fixShortNames All fixture short names\n */\n/** @type {UniqueValues} */\nconst uniqueValues = {\n  manNames: new Set(),\n  manRdmIds: new Set(),\n  fixKeysInMan: {}, // new Set() for each manufacturer\n  fixNamesInMan: {}, // new Set() for each manufacturer\n  fixRdmIdsInMan: {}, // new Set() for each manufacturer\n  fixShortNames: new Set(),\n};\n\nconst fixtureDirectoryUrl = new URL('../fixtures/', import.meta.url);\n\ntry {\n  const results = await runTests();\n\n  let totalFails = 0;\n  let totalWarnings = 0;\n\n  // each file\n  for (const result of results) {\n    const failed = result.errors.length > 0;\n    totalFails += failed ? 1 : 0;\n    totalWarnings += result.warnings.length;\n\n    printFileResult(result);\n  }\n\n  // newline\n  console.log();\n\n  // summary\n  if (totalWarnings > 0) {\n    console.log(styleText('yellow', '[INFO]'), `${totalWarnings} unresolved warning(s)`);\n  }\n\n  if (totalFails === 0) {\n    console.log(styleText('green', '[PASS]'), `All ${results.length} tested files were valid.`);\n    process.exit(0);\n  }\n\n  console.error(styleText('red', '[FAIL]'), `${totalFails} of ${results.length} tested files failed.`);\n  process.exit(1);\n}\ncatch (error) {\n  console.error(styleText('red', '[Error]'), 'Test errored:', error);\n}\n\n/**\n * @returns {Promise<object[]>} A Promise that resolves to an array of result objects.\n */\nasync function runTests() {\n  const promises = [];\n\n  if (cliArguments.a) {\n    const directoryEntries = await readdir(fixtureDirectoryUrl, { withFileTypes: true });\n    const manufacturerKeys = directoryEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);\n\n    for (const manufacturerKey of manufacturerKeys) {\n      const manufacturersDirectoryUrl = new URL(manufacturerKey, fixtureDirectoryUrl);\n\n      for (const file of await readdir(manufacturersDirectoryUrl)) {\n        if (path.extname(file) === '.json') {\n          const fixtureKey = path.basename(file, '.json');\n          promises.push(checkFixtureFile(manufacturerKey, fixtureKey));\n        }\n      }\n    }\n    promises.push(checkManufacturers());\n  }\n  else {\n    // sanitize given path\n    fixturePaths = fixturePaths.map((relativePath) => path.resolve(relativePath));\n    for (const fixturePath of fixturePaths) {\n      if (path.extname(fixturePath) !== '.json') {\n        // TODO: only produce this warning at a higher verbosity level\n        promises.push({\n          name: fixturePath,\n          errors: [],\n          warnings: ['specified file is not a .json document'],\n        });\n        continue;\n      }\n      const fixtureKey = path.basename(fixturePath, '.json');\n      const manufacturerKey = path.dirname(fixturePath).split(path.sep).pop();\n      promises.push(checkFixtureFile(manufacturerKey, fixtureKey));\n    }\n  }\n\n  return Promise.all(promises);\n}\n\n/**\n * Checks (asynchronously) the given fixture.\n * @param {string} manufacturerKey The manufacturer key.\n * @param {string} fixtureKey The fixture key.\n * @returns {Promise<object>} A Promise resolving to a result object.\n */\nasync function checkFixtureFile(manufacturerKey, fixtureKey) {\n  const filename = `${manufacturerKey}/${fixtureKey}.json`;\n  const result = {\n    name: filename,\n    errors: [],\n    warnings: [],\n  };\n\n  try {\n    const fixtureJson = await importJson(filename, fixtureDirectoryUrl);\n    Object.assign(result, await checkFixture(manufacturerKey, fixtureKey, fixtureJson, uniqueValues));\n  }\n  catch (error) {\n    result.errors.push(error);\n  }\n  return result;\n}\n\n/**\n * Checks Manufacturers file\n * @returns {Promise<object>} A Promise resolving to a result object.\n */\nasync function checkManufacturers() {\n  const result = {\n    name: 'manufacturers.json',\n    errors: [],\n    warnings: [],\n  };\n\n  try {\n    const manufacturers = await importJson(result.name, fixtureDirectoryUrl);\n    const validate = await getAjvValidator('manufacturers');\n    const valid = validate(manufacturers);\n    if (!valid) {\n      throw getAjvErrorMessages(validate.errors, 'manufacturers');\n    }\n\n    for (const [manufacturerKey, manufacturerProperties] of Object.entries(manufacturers)) {\n      if (manufacturerKey.startsWith('$')) {\n        // JSON schema property\n        continue;\n      }\n\n      // legacy purposes\n      const uniquenessTestResults = {\n        errors: [],\n      };\n      checkUniqueness(\n        uniqueValues.manNames,\n        manufacturerProperties.name,\n        uniquenessTestResults,\n        `Manufacturer name '${manufacturerProperties.name}' is not unique (test is not case-sensitive).`,\n      );\n      if ('rdmId' in manufacturerProperties) {\n        checkUniqueness(\n          uniqueValues.manRdmIds,\n          `${manufacturerProperties.rdmId}`,\n          uniquenessTestResults,\n          `Manufacturer RDM ID '${manufacturerProperties.rdmId}' is not unique.`,\n        );\n      }\n      result.errors.push(...uniquenessTestResults.errors);\n    }\n  }\n  catch (error) {\n    const isIterable = typeof error[Symbol.iterator] === 'function';\n    result.errors.push(...(isIterable ? error : [error]));\n  }\n  return result;\n}\n\n/**\n * @param {object} result The result object for a single file.\n */\nfunction printFileResult(result) {\n  const failed = result.errors.length > 0;\n\n  console.log(\n    failed ? styleText('red', '[FAIL]') : styleText('green', '[PASS]'),\n    result.name,\n  );\n\n  for (const error of result.errors) {\n    console.log('└', styleText('red', 'Error:'), error);\n  }\n\n  for (const warning of result.warnings) {\n    console.log('└', styleText('yellow', 'Warning:'), warning);\n  }\n}\n"
  },
  {
    "path": "tests/github/export-diff.js",
    "content": "#!/usr/bin/env node\n\nimport '../../lib/load-env-file.js';\n\nimport diffPluginOutputs from '../../lib/diff-plugin-outputs.js';\nimport importJson from '../../lib/import-json.js';\nimport * as pullRequest from './pull-request.js';\n\n/**\n * @typedef {object} Task\n * @property {string} manufacturerFixture The combined manufacturer / fixture key.\n * @property {string} currentPluginKey The plugin key in the current repo version.\n * @property {string} comparePluginKey The plugin key that should be compared against.\n */\n\n// generate diff tasks describing the diffed plugins, fixtures and the reason for diffing (which component has changed)\ntry {\n  await pullRequest.checkEnv();\n  await pullRequest.init();\n  const changedComponents = await pullRequest.fetchChangedComponents();\n\n  const tasks = await getDiffTasks(changedComponents);\n\n  if (tasks.length === 0) {\n    await pullRequest.updateComment({\n      fileUrl: new URL(import.meta.url),\n      name: 'Plugin export diff',\n      lines: [],\n    });\n    process.exit(0);\n  }\n\n  const lines = [\n    'You can view your uncommitted changes in plugin exports manually by executing:',\n    '`$ node cli/diff-plugin-outputs.js -p <plugin-key> [-c <compare-plugin-key>] <fixtures>`',\n    '',\n  ];\n\n  const tooLongMessage = '⚠️ The output of the script is too long to fit in this comment, please run it yourself locally!';\n\n  for (const task of tasks) {\n    const taskResultLines = await performTask(task);\n\n    // GitHub's official maximum comment length is 2**16 = 65_536, but it's actually 2**18 = 262_144.\n    // We keep 2144 characters extra space as we don't count the comment header (added by our pull request module).\n    if ([...lines, ...taskResultLines, tooLongMessage].join('\\r\\n').length > 260_000) {\n      lines.push(tooLongMessage);\n      break;\n    }\n\n    lines.push(...taskResultLines);\n  }\n\n  await pullRequest.updateComment({\n    fileUrl: new URL(import.meta.url),\n    name: 'Plugin export diff',\n    lines,\n  });\n}\ncatch (error) {\n  console.error(error);\n  process.exit(1);\n}\n\n/**\n * @param {object} changedComponents The PR's changed OFL components.\n * @returns {Promise<Task[]>} A Promise that resolves to an array of diff tasks to perform.\n */\nasync function getDiffTasks(changedComponents) {\n  const testFixtures = await importJson('../test-fixtures.json', import.meta.url);\n  const testFixtureKeys = testFixtures.map((fixture) => `${fixture.man}/${fixture.key}`);\n\n  const plugins = await importJson('../../plugins/plugins.json', import.meta.url);\n  const usablePlugins = plugins.exportPlugins.filter(\n    // don't diff new plugins and the ofl plugin (which essentially exports the source files)\n    (pluginKey) => !changedComponents.added.exports.includes(pluginKey) && pluginKey !== 'ofl',\n  );\n  const addedFixtures = new Set(changedComponents.added.fixtures.map(([manufacturer, key]) => `${manufacturer}/${key}`));\n  const usableTestFixtures = testFixtureKeys.filter((testFixture) => !addedFixtures.has(testFixture));\n\n  /** @type {Task[]} */\n  return [...getTasksForModel(), ...(await getTasksForPlugins()), ...getTasksForFixtures()]\n    .filter((task, index, array) => {\n      const firstEqualTask = array.find((otherTask) =>\n        task.manufacturerFixture === otherTask.manufacturerFixture\n        && task.currentPluginKey === otherTask.currentPluginKey\n        && task.comparePluginKey === otherTask.comparePluginKey,\n      );\n\n      // remove duplicates\n      return task === firstEqualTask;\n    })\n    .toSorted((a, b) => {\n      const manufacturerFixtureCompare = a.manufacturerFixture.localeCompare(b.manufacturerFixture);\n      const currentPluginCompare = a.currentPluginKey.localeCompare(b.currentPluginKey);\n      const comparePluginCompare = a.comparePluginKey.localeCompare(b.comparePluginKey);\n\n      if (manufacturerFixtureCompare !== 0) {\n        return manufacturerFixtureCompare;\n      }\n\n      if (currentPluginCompare !== 0) {\n        return currentPluginCompare;\n      }\n\n      return comparePluginCompare;\n    });\n\n  /**\n   * @returns {Task[]} What export diff tasks have to be done due to changes in the model. May be empty.\n   */\n  function getTasksForModel() {\n    const tasks = [];\n\n    if (\n      changedComponents.added.model\n      || changedComponents.modified.model\n      || changedComponents.removed.model\n    ) {\n      for (const manufacturerFixture of usableTestFixtures) {\n        tasks.push(...usablePlugins.map((pluginKey) => ({\n          manufacturerFixture,\n          currentPluginKey: pluginKey,\n          comparePluginKey: pluginKey,\n        })));\n      }\n    }\n\n    return tasks;\n  }\n\n  /**\n   * @returns {Promise<Task[]>} A Promise that resolves to what export diff tasks have to be done due to changes in plugins. May be empty.\n   */\n  async function getTasksForPlugins() {\n    const tasks = [];\n\n    const changedPlugins = changedComponents.modified.exports;\n    for (const changedPlugin of changedPlugins) {\n      tasks.push(...usableTestFixtures.map((manufacturerFixture) => ({\n        manufacturerFixture,\n        currentPluginKey: changedPlugin,\n        comparePluginKey: changedPlugin,\n      })));\n    }\n\n    const addedPlugins = changedComponents.added.exports;\n    const removedPlugins = changedComponents.removed.exports;\n    for (const addedPlugin of addedPlugins) {\n      const pluginData = await importJson(`../../plugins/${addedPlugin}/plugin.json`, import.meta.url);\n\n      if (pluginData.previousVersions) {\n        const previousVersions = Object.keys(pluginData.previousVersions);\n        const lastVersion = previousVersions.at(-1);\n\n        if (removedPlugins.includes(lastVersion) || (plugins.exportPlugins.includes(lastVersion) && !addedPlugins.includes(lastVersion))) {\n          tasks.push(...usableTestFixtures.map((manufacturerFixture) => ({\n            manufacturerFixture,\n            currentPluginKey: addedPlugin,\n            comparePluginKey: lastVersion,\n          })));\n        }\n      }\n    }\n\n    return tasks;\n  }\n\n  /**\n   * @returns {Task[]} What export diff tasks have to be done due to changes in fixtures. May be empty.\n   */\n  function getTasksForFixtures() {\n    const tasks = [];\n\n    for (const [manufacturerKey, fixtureKey] of changedComponents.modified.fixtures) {\n      tasks.push(...usablePlugins.map((pluginKey) => ({\n        manufacturerFixture: `${manufacturerKey}/${fixtureKey}`,\n        currentPluginKey: pluginKey,\n        comparePluginKey: pluginKey,\n      })));\n    }\n\n    return tasks;\n  }\n}\n\n/**\n * @param {Task} task The export diff task to fulfill.\n * @returns {Promise<string[]>} An array of message lines.\n */\nasync function performTask(task) {\n  const output = await diffPluginOutputs(task.currentPluginKey, task.comparePluginKey, process.env.GITHUB_PR_BASE_REF, [task.manufacturerFixture]);\n  const changeFlags = getChangeFlags(output);\n  const emoji = getEmoji(changeFlags);\n\n  const pluginDisplayName = task.currentPluginKey === task.comparePluginKey ? task.currentPluginKey : `${task.comparePluginKey}->${task.currentPluginKey}`;\n\n  const lines = [\n    '<details>',\n    `<summary>${emoji} <strong>${task.manufacturerFixture}:</strong> ${pluginDisplayName}</summary>`,\n  ];\n\n  if (changeFlags.nothingChanged) {\n    lines.push('Outputted files not changed.');\n  }\n  else {\n    lines.push('<blockquote>');\n\n    if (changeFlags.hasRemoved) {\n      lines.push(\n        '<strong>Removed files</strong>',\n        '<ul>',\n        ...output.removedFiles.map((file) => `<li>${file}</li>`),\n        '</ul>',\n      );\n    }\n\n    if (changeFlags.hasAdded) {\n      lines.push(\n        '<strong>Added files</strong>',\n        '<ul>',\n        ...output.addedFiles.map((file) => `<li>${file}</li>`),\n        '</ul>',\n      );\n    }\n\n    for (const file of Object.keys(output.changedFiles)) {\n      lines.push(\n        '<details>',\n        `<summary><strong>Changed outputted file <code>${file}</code></strong></summary>`,\n        '',\n        '```diff',\n        output.changedFiles[file],\n        '```',\n        '</details>',\n      );\n    }\n\n    lines.push('</blockquote>');\n  }\n\n  lines.push('</details>');\n\n  return lines;\n}\n\n/**\n * @typedef {object} ChangeFlags\n * @property {boolean} hasRemoved Whether any files were removed.\n * @property {boolean} hasAdded Whether any files were added.\n * @property {boolean} hasChanged Whether any files were changed.\n * @property {boolean} nothingChanged Whether changed at all.\n */\n\n/**\n * @param {object} diffOutput Output object from {@link diffPluginOutputs}.\n * @returns {ChangeFlags} Object with change flags.\n */\nfunction getChangeFlags(diffOutput) {\n  const hasRemoved = diffOutput.removedFiles.length > 0;\n  const hasAdded = diffOutput.addedFiles.length > 0;\n  const hasChanged = Object.keys(diffOutput.changedFiles).length > 0;\n\n  return {\n    hasRemoved,\n    hasAdded,\n    hasChanged,\n    nothingChanged: !hasRemoved && !hasAdded && !hasChanged,\n  };\n}\n\n/**\n * @param {ChangeFlags} changeFlags Object with flags that tell what changed.\n * @returns {string} String containing a GitHub emoji depicting the changes.\n */\nfunction getEmoji(changeFlags) {\n  if (changeFlags.nothingChanged) {\n    return '💤';\n  }\n\n  if (changeFlags.hasChanged || (changeFlags.hasAdded && changeFlags.hasRemoved)) {\n    return '🆚';\n  }\n\n  if (changeFlags.hasAdded) {\n    return '🆕';\n  }\n\n  return '❌';\n}\n"
  },
  {
    "path": "tests/github/exports-valid.js",
    "content": "#!/usr/bin/env node\n\nimport { fileURLToPath } from 'url';\nimport importJson from '../../lib/import-json.js';\nimport { fixtureFromRepository } from '../../lib/model.js';\nimport * as pullRequest from './pull-request.js';\n\nlet plugins;\nlet exportTests;\nlet testFixtureKeys;\n\nlet testErrored = false;\n\n/**\n * @typedef {object} Task\n * @property {string} manufacturerKey The manufacturer key of the fixture that should be tested.\n * @property {string} fixtureKey The key of the fixture that should be tested.\n * @property {string} pluginKey The key of the export plugin whose output should be tested.\n * @property {string} testKey The key of the export test that should be executed.\n */\n\ntry {\n  await pullRequest.checkEnv();\n  await pullRequest.init();\n  const changedComponents = await pullRequest.fetchChangedComponents();\n\n  plugins = await importJson('../../plugins/plugins.json', import.meta.url);\n\n  exportTests = [];\n  for (const exportPluginKey of plugins.exportPlugins) {\n    const plugin = plugins.data[exportPluginKey];\n\n    exportTests.push(...plugin.exportTests.map(\n      (testKey) => [exportPluginKey, testKey],\n    ));\n  }\n\n  const testFixtures = await importJson('../test-fixtures.json', import.meta.url);\n  testFixtureKeys = testFixtures.map((fixture) => [fixture.man, fixture.key]);\n\n  const tasks = [\n    ...getTasksForModel(changedComponents),\n    ...getTasksForPlugins(changedComponents),\n    ...getTasksForExportTests(changedComponents),\n    ...getTasksForFixtures(changedComponents),\n  ]\n    .filter((task, index, array) => {\n      const firstEqualTask = array.find((otherTask) =>\n        task.manufacturerKey === otherTask.manufacturerKey\n        && task.fixtureKey === otherTask.fixtureKey\n        && task.pluginKey === otherTask.pluginKey\n        && task.testKey === otherTask.testKey,\n      );\n\n      // remove duplicates\n      return task === firstEqualTask;\n    })\n    .toSorted((a, b) => {\n      const manufacturerCompare = a.manufacturerKey.localeCompare(b.manufacturerKey);\n      const fixtureCompare = a.fixtureKey.localeCompare(b.fixtureKey);\n      const pluginCompare = a.pluginKey.localeCompare(b.pluginKey);\n      const testCompare = a.testKey.localeCompare(b.testKey);\n\n      if (manufacturerCompare !== 0) {\n        return manufacturerCompare;\n      }\n\n      if (fixtureCompare !== 0) {\n        return fixtureCompare;\n      }\n\n      if (pluginCompare !== 0) {\n        return pluginCompare;\n      }\n\n      return testCompare;\n    });\n\n  if (tasks.length === 0) {\n    await pullRequest.updateComment({\n      fileUrl: new URL(import.meta.url),\n      name: 'Export files validity',\n      lines: [],\n    });\n    process.exit(0);\n  }\n\n  const lines = [\n    'Test the exported files of selected fixtures against the plugins\\' export tests.',\n    'You can run a plugin\\'s export tests by executing:',\n    '`$ node cli/run-export-test.js -p <plugin name> <fixtures>`',\n    '',\n  ];\n\n  const tooLongMessage = '⚠️ The output of the script is too long to fit in this comment, please run it yourself locally!';\n\n  for (const task of tasks) {\n    const taskResultLines = await getTaskPromise(task);\n\n    // GitHub's official maximum comment length is 2**16 = 65_536, but it's actually 2**18 = 262_144.\n    // We keep 2144 characters extra space as we don't count the comment header (added by our pull request module).\n    if ([...lines, ...taskResultLines, tooLongMessage].join('\\r\\n').length > 260_000) {\n      lines.push(tooLongMessage);\n      break;\n    }\n\n    lines.push(...taskResultLines);\n  }\n\n  await pullRequest.updateComment({\n    fileUrl: new URL(import.meta.url),\n    name: 'Export files validity',\n    lines,\n  });\n\n  if (testErrored) {\n    throw new Error('Unable to export some fixtures.');\n  }\n}\ncatch (error) {\n  console.error(error);\n  process.exit(1);\n}\n\n/**\n * @param {[pluginKey: string, testKey: string][]} tests An array of export tests.\n * @param {string} manufacturerKey The manufacturer key of the fixture that should be tested.\n * @param {string} fixtureKey The key of the fixture that should be tested.\n * @returns {Task[]} An array of export valid tasks.\n */\nfunction mapExportTestsToTasks(tests, manufacturerKey, fixtureKey) {\n  return tests.map(([pluginKey, testKey]) => ({\n    manufacturerKey,\n    fixtureKey,\n    pluginKey,\n    testKey,\n  }));\n}\n\n/**\n * @param {object} changedComponents What components have been changed in this PR.\n * @returns {Task[]} What export valid tasks have to be done due to changes in the model. May be empty.\n */\nfunction getTasksForModel(changedComponents) {\n  const tasks = [];\n\n  if (\n    changedComponents.added.model\n    || changedComponents.modified.model\n    || changedComponents.removed.model\n  ) {\n    for (const [manufacturerKey, fixtureKey] of testFixtureKeys) {\n      tasks.push(...mapExportTestsToTasks(exportTests, manufacturerKey, fixtureKey));\n    }\n  }\n\n  return tasks;\n}\n\n/**\n * @param {object} changedComponents What components have been changed in this PR.\n * @returns {Task[]} What export valid tasks have to be done due to changes in plugins. May be empty.\n */\nfunction getTasksForPlugins(changedComponents) {\n  const tasks = [];\n\n  const changedPlugins = [...changedComponents.added.exports, ...changedComponents.modified.exports];\n\n  for (const changedPlugin of changedPlugins) {\n    const pluginExportTests = plugins.data[changedPlugin].exportTests;\n\n    for (const [manufacturerKey, fixtureKey] of testFixtureKeys) {\n      tasks.push(...pluginExportTests.map((testKey) => ({\n        manufacturerKey,\n        fixtureKey,\n        pluginKey: changedPlugin,\n        testKey,\n      })));\n    }\n  }\n\n  return tasks;\n}\n\n/**\n * @param {object} changedComponents What components have been changed in this PR.\n * @returns {Task[]} What export valid tasks have to be done due to changes in export tests. May be empty.\n */\nfunction getTasksForExportTests(changedComponents) {\n  const tasks = [];\n\n  const changedExportTests = [...changedComponents.added.exportTests, ...changedComponents.modified.exportTests];\n\n  for (const [manufacturerKey, fixtureKey] of testFixtureKeys) {\n    tasks.push(...mapExportTestsToTasks(changedExportTests, manufacturerKey, fixtureKey));\n  }\n\n  return tasks;\n}\n\n/**\n * @param {object} changedComponents What components have been changed in this PR.\n * @returns {Task[]} What export valid tasks have to be done due to changes in fixtures. May be empty.\n */\nfunction getTasksForFixtures(changedComponents) {\n  const tasks = [];\n\n  const fixtures = [...changedComponents.added.fixtures, ...changedComponents.modified.fixtures];\n\n  for (const [manufacturerKey, fixtureKey] of fixtures) {\n    tasks.push(...mapExportTestsToTasks(exportTests, manufacturerKey, fixtureKey));\n  }\n\n  return tasks;\n}\n\n/**\n * @param {Task} task The export valid task to fulfill.\n * @returns {Promise} A promise resolving with an array of message lines.\n */\nasync function getTaskPromise(task) {\n  const plugin = await import(`../../plugins/${task.pluginKey}/export.js`);\n  const { default: test } = await import(`../../plugins/${task.pluginKey}/exportTests/${task.testKey}.js`);\n\n  let emoji = '✔️';\n  const detailListItems = [];\n\n  try {\n    const files = await plugin.exportFixtures(\n      [await fixtureFromRepository(task.manufacturerKey, task.fixtureKey)],\n      {\n        baseDirectory: fileURLToPath(new URL('../../', import.meta.url)),\n        date: new Date(),\n      },\n    );\n\n    const resultListItems = await Promise.all(files.map(async (file) => {\n      try {\n        await test(file, files);\n        return `✔️ ${file.name}`;\n      }\n      catch (error) {\n        emoji = '❌';\n        const errors = [error].flat().join('<br />\\n');\n        return `<details><summary>❌ ${file.name}</summary>${errors}</details>`;\n      }\n    }));\n    detailListItems.push(...resultListItems);\n  }\n  catch (error) {\n    emoji = '❗';\n    detailListItems.push(`Unable to export fixture: ${error.message}`);\n    testErrored = true;\n  }\n\n  return [\n    '<details>',\n    `  <summary>${emoji} <strong>${task.manufacturerKey} / ${task.fixtureKey}:</strong> ${task.pluginKey} / ${task.testKey}</summary>`,\n    '  <ul>',\n    ...detailListItems.map((listItem) => `    <li>${listItem}</li>`),\n    '  </ul>',\n    '</details>',\n  ];\n}\n"
  },
  {
    "path": "tests/github/pull-request.js",
    "content": "import '../../lib/load-env-file.js';\n\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { styleText } from 'util';\nimport { Octokit } from '@octokit/rest';\n\nconst requiredEnvironmentVariables = [\n  'GITHUB_USER_TOKEN',\n  'GITHUB_REPOSITORY',\n  'GITHUB_PR_NUMBER',\n  'GITHUB_PR_HEAD_REF',\n  'GITHUB_PR_BASE_REF',\n];\n\n/** @type {Octokit} */\nlet githubClient;\n\nlet repoOwner;\nlet repoName;\nlet prData;\n\n/**\n * Checks if the environment variables for GitHub operations are correct.\n * @returns {Promise} Rejects an error message if the environment is not correct.\n */\nexport async function checkEnv() {\n  for (const environmentVariable of requiredEnvironmentVariables) {\n    if (!(environmentVariable in process.env)) {\n      throw `Environment variable ${environmentVariable} is required for this script. Please define it in your system or in the .env file.`;\n    }\n  }\n}\n\n/**\n * Fetch data about the current pull request from the GitHub API.\n * @returns {Promise} A Promise that resolves to the returned pull request data.\n */\nexport async function init() {\n  await checkEnv();\n\n  repoOwner = process.env.GITHUB_REPOSITORY.split('/')[0];\n  repoName = process.env.GITHUB_REPOSITORY.split('/')[1];\n\n  githubClient = new Octokit({\n    auth: `token ${process.env.GITHUB_USER_TOKEN}`,\n  });\n\n  const pr = await githubClient.rest.pulls.get({\n    owner: repoOwner,\n    repo: repoName,\n    // eslint-disable-next-line camelcase -- required by GitHub API\n    pull_number: process.env.GITHUB_PR_NUMBER,\n  });\n\n  // save PR for later use\n  prData = pr.data;\n\n  return pr.data;\n}\n\n/**\n * @returns {Promise} A Promise that resolves to an object which describes the OFL components changed in this pull request.\n */\nexport async function fetchChangedComponents() {\n  // fetch changed files in blocks of 100\n  const filePromises = [];\n  for (let index = 0; index < prData.changed_files / 100; index++) {\n    filePromises.push(githubClient.rest.pulls.listFiles({\n      owner: repoOwner,\n      repo: repoName,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      pull_number: process.env.GITHUB_PR_NUMBER,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      per_page: 100,\n      page: index + 1,\n    }));\n  }\n\n  // check which model components, plugins and fixtures have been changed in the PR\n  const fileBlocks = await Promise.all(filePromises);\n\n  const changedComponents = {\n    added: {\n      schema: false,\n      model: false,\n      imports: [], // array of plugin keys\n      exports: [], // array of plugin keys\n      exportTests: [], // array of [plugin key, test key]\n      fixtures: [], // array of [man key, fix key]\n    },\n    modified: {\n      schema: false,\n      model: false,\n      imports: [], // array of plugin keys\n      exports: [], // array of plugin keys\n      exportTests: [], // array of [plugin key, test key]\n      fixtures: [], // array of [man key, fix key]\n    },\n    removed: {\n      schema: false,\n      model: false,\n      imports: [], // array of plugin keys\n      exports: [], // array of plugin keys\n      exportTests: [], // array of [plugin key, test key]\n      fixtures: [], // array of [man key, fix key]\n    },\n  };\n\n  for (const block of fileBlocks) {\n    for (const fileData of block.data) {\n      handleFileData(fileData);\n    }\n  }\n\n  return changedComponents;\n\n  /**\n   * Forwards the file's status and path to handleFile(...) with the specialty of splitting renamed files into added/removed.\n   * @param {object} fileData The file object from GitHub.\n   */\n  function handleFileData(fileData) {\n    if (fileData.status === 'renamed') {\n      // Handling renamed files would be a bit tricky, as we also had to store the previous filename.\n      // That's why we simply treat the old file name as removed and the new one as added.\n      handleFile('added', fileData.filename);\n      handleFile('removed', fileData.previous_filename);\n    }\n    else {\n      handleFile(fileData.status, fileData.filename);\n    }\n  }\n\n  /**\n   * Parse the file type by its path and update the change summary of the file's status accordingly.\n   * @param {'added' | 'removed' | 'modified'} fileStatus What happened with the file in this pull request.\n   * @param {string} filePath The file name, relative to the repository's root.\n   */\n  function handleFile(fileStatus, filePath) {\n    const changeSummary = changedComponents[fileStatus];\n    const segments = filePath.split('/');\n\n    if (segments[0] === 'lib' && segments[1] === 'model') {\n      changeSummary.model = true;\n      return;\n    }\n\n    if (segments[0] === 'plugins' && segments[2] === 'import.js') {\n      changeSummary.imports.push(segments[1]); // plugin key\n      return;\n    }\n\n    if (segments[0] === 'plugins' && segments[2] === 'export.js') {\n      changeSummary.exports.push(segments[1]); // plugin key\n      return;\n    }\n\n    if (segments[0] === 'plugins' && segments[2] === 'exportTests') {\n      changeSummary.exportTests.push([\n        segments[1], // plugin key\n        segments[3].split('.')[0], // test key\n      ]);\n      return;\n    }\n\n    if (segments[0] === 'schemas') {\n      changeSummary.schema = true;\n      return;\n    }\n\n    if (segments[0] === 'fixtures' && segments.length === 3) {\n      changeSummary.fixtures.push([\n        segments[1], // man key\n        segments[2].split('.')[0], // fix key\n      ]);\n    }\n  }\n}\n\n/**\n * Creates a new comment in the PR if test.lines is not empty and if there is not already an exactly equal comment.\n * Deletes old comments from the same test (determined by test.fileUrl).\n * @param {object} test Information about the test script that wants to update the comment.\n * @param {URL} test.fileUrl URL of the test file.\n * @param {string} test.name Heading to be used in the comment\n * @param {string[]} test.lines The comment's lines of text\n * @returns {Promise} A Promise that is fulfilled as soon as all GitHub operations have finished\n */\nexport async function updateComment(test) {\n  if (prData.head.repo.full_name !== prData.base.repo.full_name) {\n    console.warn(styleText('yellow', 'Warning:'), 'This PR is created from a forked repository, so there is no write permission for the repo.');\n    return undefined;\n  }\n\n  const oflRootPath = fileURLToPath(new URL('../../', import.meta.url));\n  const relativeFilePath = path.relative(oflRootPath, fileURLToPath(test.fileUrl));\n\n  const lines = [\n    `<!-- GITHUB-TEST: ${relativeFilePath} -->`,\n    `# ${test.name}`,\n    `(Output of test script \\`${relativeFilePath}\\`.)`,\n    '',\n    ...test.lines,\n  ];\n  const message = lines.join('\\n');\n\n  const commentPromises = [];\n  for (let index = 0; index < prData.comments / 100; index++) {\n    commentPromises.push(\n      githubClient.rest.issues.listComments({\n        owner: repoOwner,\n        repo: repoName,\n        // eslint-disable-next-line camelcase -- required by GitHub API\n        issue_number: process.env.GITHUB_PR_NUMBER,\n        // eslint-disable-next-line camelcase -- required by GitHub API\n        per_page: 100,\n        page: index + 1,\n      }),\n    );\n  }\n\n  const commentBlocks = await Promise.all(commentPromises);\n  const comments = commentBlocks.flatMap((block) => block.data);\n\n  let equalFound = false;\n  const promises = comments.flatMap((comment) => {\n    // get rid of \\r linebreaks\n    comment.body = comment.body.replaceAll('\\r', '');\n\n    if (lines[0] !== comment.body.split('\\n')[0]) {\n      // the comment was not created by this test script\n      return [];\n    }\n\n    if (!equalFound && message === comment.body && test.lines.length > 0) {\n      equalFound = true;\n      console.log(`Test comment with same content already exists at ${process.env.GITHUB_REPOSITORY}#${process.env.GITHUB_PR_NUMBER}.`);\n      return [];\n    }\n\n    console.log(`Deleting old test comment at ${process.env.GITHUB_REPOSITORY}#${process.env.GITHUB_PR_NUMBER}.`);\n\n    return githubClient.rest.issues.deleteComment({\n      owner: repoOwner,\n      repo: repoName,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      comment_id: comment.id,\n    });\n  });\n\n  if (!equalFound && test.lines.length > 0) {\n    console.log(`Creating test comment at ${process.env.GITHUB_REPOSITORY}#${process.env.GITHUB_PR_NUMBER}.`);\n    promises.push(githubClient.rest.issues.createComment({\n      owner: repoOwner,\n      repo: repoName,\n      // eslint-disable-next-line camelcase -- required by GitHub API\n      issue_number: process.env.GITHUB_PR_NUMBER,\n      body: message,\n    }));\n  }\n\n  return Promise.all(promises);\n}\n"
  },
  {
    "path": "tests/github/schema-version-reminder.js",
    "content": "#!/usr/bin/env node\n\nimport '../../lib/load-env-file.js';\n\nimport * as pullRequest from './pull-request.js';\n\ntry {\n  await pullRequest.checkEnv();\n  await pullRequest.init();\n  const changedComponents = await pullRequest.fetchChangedComponents();\n\n  const lines = [];\n\n  if (\n    changedComponents.added.schema\n    || changedComponents.modified.schema\n    || changedComponents.removed.schema\n  ) {\n    lines.push(`With every change on the schema, its version should be incremented and tagged. See the [Fixture README](https://github.com/OpenLightingProject/open-fixture-library/blob/${process.env.GITHUB_PR_HEAD_REF}/docs/fixture-format.md#schema) for further information.`);\n  }\n\n  await pullRequest.updateComment({\n    fileUrl: new URL(import.meta.url),\n    name: 'Schema has changed',\n    lines,\n  });\n}\ncatch (error) {\n  console.error(error);\n  process.exit(1);\n}\n"
  },
  {
    "path": "tests/http-status.test.js",
    "content": "import '../lib/load-env-file.js';\n\nimport { styleText } from 'util';\nimport { afterAll, beforeAll, describe, expect, it } from 'vitest';\nimport SiteCrawler from '../lib/site-crawler.js';\n\ndescribe('http-status', () => {\n  /** @type {string[]} */\n  const failingLinks = [];\n\n  const crawler = new SiteCrawler();\n\n  beforeAll(async () => {\n    await crawler.startServer();\n\n    crawler.addEventListener('passingPage', ({ url }) => {\n      console.log(styleText('greenBright', '[PASS]'), url);\n    });\n    crawler.addEventListener('failingPage', ({ url, error }) => {\n      const coloredError = styleText('redBright', error);\n      console.log(styleText('redBright', '[FAIL]'), `${url} (${coloredError})`);\n      failingLinks.push(`${url} (${error})`);\n    });\n  }, 30_000);\n\n  afterAll(async () => {\n    await crawler.stopServer();\n  });\n\n  it('should have no failing internal links', async () => {\n    await crawler.crawl();\n\n    const failingLinksText = failingLinks.join('\\n');\n    expect(failingLinks, `Failing links:\\n${failingLinksText}`).toStrictEqual([]);\n  }, 10 * 60_000);\n});\n"
  },
  {
    "path": "tests/test-fixtures.json",
    "content": "[\n  {\n    \"man\": \"afx\",\n    \"key\": \"lmh460z\",\n    \"name\": \"LMH460Z\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-Effect\",\n      \"capability-type-Zoom\",\n      \"capability-type-Maintenance\",\n      \"capability-type-Generic\",\n      \"fine-channel-alias\",\n      \"fine-positions-1\",\n      \"floating-point-lumens\",\n      \"multiple-categories\"\n    ]\n  },\n  {\n    \"man\": \"astera\",\n    \"key\": \"fp3-hyperion-tube\",\n    \"name\": \"FP3 Hyperion Tube\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-ColorTemperature\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-EffectParameter\",\n      \"capability-type-Time\",\n      \"capability-type-Generic\",\n      \"duplicate-channel-names\",\n      \"fine-channel-alias\",\n      \"floating-point-weight\",\n      \"many-modes\",\n      \"matrix-pixelCount\",\n      \"matrix-pixelGroups\",\n      \"matrix-pixelGroups-number-constraints\",\n      \"fine-matrix-channel\",\n      \"matrix-channel-used-directly\",\n      \"multiple-categories\",\n      \"null-channels\",\n      \"reused-channels\"\n    ]\n  },\n  {\n    \"man\": \"ayrton\",\n    \"key\": \"diablo-tc\",\n    \"name\": \"Diablo-TC\",\n    \"features\": [\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorTemperature\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelSlotRotation\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-Focus\",\n      \"capability-type-Zoom\",\n      \"capability-type-Iris\",\n      \"capability-type-IrisEffect\",\n      \"capability-type-Frost\",\n      \"capability-type-Prism\",\n      \"capability-type-PrismRotation\",\n      \"capability-type-BladeInsertion\",\n      \"capability-type-BladeSystemRotation\",\n      \"capability-type-Time\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"fine-channel-capabilities\",\n      \"floating-point-dimensions\",\n      \"floating-point-weight\",\n      \"floating-point-lens-degrees\",\n      \"multiple-categories\",\n      \"reused-channels\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-type-AnimationGobo\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\",\n      \"wheel-slot-type-AnimationGoboStart\",\n      \"wheel-slot-type-AnimationGoboEnd\"\n    ]\n  },\n  {\n    \"man\": \"cameo\",\n    \"key\": \"auro-beam-150\",\n    \"name\": \"Auro Beam 150\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-Pan\",\n      \"capability-type-PanContinuous\",\n      \"capability-type-Tilt\",\n      \"capability-type-TiltContinuous\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-SoundSensitivity\",\n      \"capability-type-Maintenance\",\n      \"duplicate-channel-names\",\n      \"fine-channel-alias\",\n      \"fine-positions-1\",\n      \"floating-point-weight\",\n      \"matrix-pixelKeys\",\n      \"matrix-pixelGroups\",\n      \"matrix-custom-layout\",\n      \"matrix-channel-used-directly\",\n      \"multiple-categories\",\n      \"multiple-focuses\",\n      \"reused-channels\",\n      \"switching-channels\",\n      \"switching-channel-positions\"\n    ]\n  },\n  {\n    \"man\": \"cameo\",\n    \"key\": \"auro-spot-400\",\n    \"name\": \"Auro Spot 400\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelSlotRotation\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-Focus\",\n      \"capability-type-Frost\",\n      \"capability-type-Speed\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"floating-point-weight\",\n      \"multiple-categories\",\n      \"reused-channels\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-type-Prism\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\",\n      \"wheel-slot-type-Prism\"\n    ]\n  },\n  {\n    \"man\": \"cameo\",\n    \"key\": \"hydrabeam-300-rgbw\",\n    \"name\": \"Hydrabeam 300 RGBW\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-SoundSensitivity\",\n      \"capability-type-Maintenance\",\n      \"duplicate-channel-names\",\n      \"fine-channel-alias\",\n      \"fine-positions-1\",\n      \"floating-point-weight\",\n      \"floating-point-lens-degrees\",\n      \"matrix-pixelKeys\",\n      \"matrix-custom-layout\",\n      \"fine-matrix-channel\",\n      \"switching-matrix-channel\",\n      \"matrix-channel-overridden\",\n      \"multiple-categories\",\n      \"multiple-focuses\",\n      \"reused-channels\",\n      \"switching-channels\",\n      \"switching-channel-positions\"\n    ]\n  },\n  {\n    \"man\": \"flash-professional\",\n    \"key\": \"led-moving-head-150w\",\n    \"name\": \"LED Moving Head 150W\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelSlotRotation\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-Focus\",\n      \"capability-type-Zoom\",\n      \"capability-type-Frost\",\n      \"capability-type-Prism\",\n      \"capability-type-PrismRotation\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"multiple-categories\",\n      \"reused-channels\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-type-Iris\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\",\n      \"wheel-slot-type-Iris\"\n    ]\n  },\n  {\n    \"man\": \"generic\",\n    \"key\": \"pan-tilt\",\n    \"name\": \"Pan/Tilt Fader\",\n    \"features\": [\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"fine-channel-aliases\",\n      \"fine-positions-1\",\n      \"no-physical-data\",\n      \"reused-channels\"\n    ]\n  },\n  {\n    \"man\": \"glp\",\n    \"key\": \"impression-laser\",\n    \"name\": \"impression Laser\",\n    \"features\": [\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-BeamAngle\",\n      \"capability-type-BeamPosition\",\n      \"capability-type-Zoom\",\n      \"capability-type-Rotation\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"floating-point-weight\",\n      \"multiple-categories\"\n    ]\n  },\n  {\n    \"man\": \"glp\",\n    \"key\": \"knv-arc\",\n    \"name\": \"KNV Arc\",\n    \"features\": [\n      \"16bit-capability-range\",\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-StrobeDuration\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-EffectDuration\",\n      \"capability-type-EffectParameter\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"fine-channel-capabilities\",\n      \"floating-point-weight\",\n      \"matrix-pixelKeys\",\n      \"matrix-pixelGroups\",\n      \"matrix-custom-layout\",\n      \"fine-matrix-channel\",\n      \"switching-matrix-channel\",\n      \"matrix-channel-used-directly\",\n      \"multiple-categories\",\n      \"reused-channels\",\n      \"switching-channels\",\n      \"switching-channel-positions\"\n    ]\n  },\n  {\n    \"man\": \"lixada\",\n    \"key\": \"mini-moving-head-rgbw\",\n    \"name\": \"Mini Moving Head RGBW\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"floating-point-weight\",\n      \"multiple-categories\",\n      \"redirect-reason-SameAsDifferentBrand\",\n      \"reused-channels\"\n    ]\n  },\n  {\n    \"man\": \"martin\",\n    \"key\": \"mac-axiom-hybrid\",\n    \"name\": \"MAC Axiom Hybrid\",\n    \"features\": [\n      \"16bit-capability-range\",\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorTemperature\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelSlotRotation\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-BeamAngle\",\n      \"capability-type-Focus\",\n      \"capability-type-Zoom\",\n      \"capability-type-Frost\",\n      \"capability-type-Prism\",\n      \"capability-type-PrismRotation\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"fine-channel-capabilities\",\n      \"floating-point-weight\",\n      \"multiple-categories\",\n      \"switching-channels\",\n      \"switches-fine-channels\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\",\n      \"wheel-slot-type-Iris\",\n      \"wheel-slot-type-Frost\",\n      \"wheel-slot-type-AnimationGoboStart\",\n      \"wheel-slot-type-AnimationGoboEnd\"\n    ]\n  },\n  {\n    \"man\": \"martin\",\n    \"key\": \"mac-encore-performance\",\n    \"name\": \"MAC Encore Performance\",\n    \"features\": [\n      \"16bit-capability-range\",\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorTemperature\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelSlotRotation\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-Focus\",\n      \"capability-type-Zoom\",\n      \"capability-type-Iris\",\n      \"capability-type-IrisEffect\",\n      \"capability-type-Frost\",\n      \"capability-type-BladeInsertion\",\n      \"capability-type-BladeRotation\",\n      \"capability-type-BladeSystemRotation\",\n      \"capability-type-Maintenance\",\n      \"capability-type-Generic\",\n      \"fine-channel-alias\",\n      \"fine-channel-capabilities\",\n      \"multiple-categories\",\n      \"physical-override\",\n      \"reused-channels\",\n      \"switching-channels\",\n      \"switches-fine-channels\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-type-AnimationGobo\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\",\n      \"wheel-slot-type-AnimationGoboStart\",\n      \"wheel-slot-type-AnimationGoboEnd\"\n    ]\n  },\n  {\n    \"man\": \"martin\",\n    \"key\": \"mania-scx500\",\n    \"name\": \"Mania SCX500\",\n    \"features\": [\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-Speed\",\n      \"capability-type-Maintenance\",\n      \"capability-type-Generic\",\n      \"floating-point-weight\",\n      \"multiple-categories\",\n      \"reused-channels\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Closed\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\"\n    ]\n  },\n  {\n    \"man\": \"mdg\",\n    \"key\": \"theone-atmospheric-generator\",\n    \"name\": \"theONE Atmospheric Generator\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-Fog\",\n      \"capability-type-FogOutput\",\n      \"capability-type-FogType\",\n      \"capability-type-Rotation\",\n      \"capability-type-Maintenance\",\n      \"multiple-categories\",\n      \"rdm\"\n    ]\n  },\n  {\n    \"man\": \"prolights\",\n    \"key\": \"diamond19\",\n    \"name\": \"DIAMOND19\",\n    \"features\": [\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-StrobeSpeed\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-ColorTemperature\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-Zoom\",\n      \"capability-type-Maintenance\",\n      \"capability-type-Generic\",\n      \"duplicate-channel-names\",\n      \"fine-channel-alias\",\n      \"matrix-pixelKeys\",\n      \"matrix-pixelGroups\",\n      \"matrix-pixelGroups-string-constraints\",\n      \"matrix-custom-layout\",\n      \"multiple-categories\",\n      \"reused-channels\",\n      \"switching-channels\",\n      \"switching-channel-positions\"\n    ]\n  },\n  {\n    \"man\": \"qtx\",\n    \"key\": \"lux-ld01\",\n    \"name\": \"Lux Ld01\",\n    \"features\": [\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"fine-channel-alias\",\n      \"floating-point-weight\",\n      \"floating-point-power\",\n      \"multiple-categories\",\n      \"reused-channels\",\n      \"wheel-type-Gobo\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Gobo\"\n    ]\n  },\n  {\n    \"man\": \"robe\",\n    \"key\": \"robin-viva-cmy\",\n    \"name\": \"ROBIN Viva CMY\",\n    \"features\": [\n      \"16bit-capability-range\",\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelSlotRotation\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-EffectSpeed\",\n      \"capability-type-Focus\",\n      \"capability-type-Zoom\",\n      \"capability-type-Iris\",\n      \"capability-type-IrisEffect\",\n      \"capability-type-Frost\",\n      \"capability-type-FrostEffect\",\n      \"capability-type-Prism\",\n      \"capability-type-PrismRotation\",\n      \"capability-type-Time\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"fine-channel-capabilities\",\n      \"multiple-categories\",\n      \"rdm\",\n      \"reused-channels\",\n      \"switching-channels\",\n      \"switches-fine-channels\",\n      \"switching-channel-positions\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\"\n    ]\n  },\n  {\n    \"man\": \"stairville\",\n    \"key\": \"mh-x30\",\n    \"name\": \"MH-x30\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelSlotRotation\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Focus\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"floating-point-weight\",\n      \"multiple-categories\",\n      \"redirect-reason-FixtureRenamed\",\n      \"reused-channels\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\"\n    ]\n  },\n  {\n    \"man\": \"varytec\",\n    \"key\": \"hero-spot-230\",\n    \"name\": \"Hero Spot 230\",\n    \"features\": [\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelSlotRotation\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-Focus\",\n      \"capability-type-Zoom\",\n      \"capability-type-Prism\",\n      \"capability-type-PrismRotation\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"floating-point-weight\",\n      \"reused-channels\",\n      \"wheel-type-Color\",\n      \"wheel-type-Gobo\",\n      \"wheel-slot-type-Open\",\n      \"wheel-slot-type-Color\",\n      \"wheel-slot-type-Gobo\",\n      \"wheel-slot-uses-resource\"\n    ]\n  },\n  {\n    \"man\": \"varytec\",\n    \"key\": \"hero-wash-340fx-rgbw-zoom\",\n    \"name\": \"Hero Wash 340FX RGBW Zoom\",\n    \"features\": [\n      \"16bit-default-value\",\n      \"capability-type-NoFunction\",\n      \"capability-type-ShutterStrobe\",\n      \"capability-type-Intensity\",\n      \"capability-type-ColorIntensity\",\n      \"capability-type-ColorPreset\",\n      \"capability-type-ColorTemperature\",\n      \"capability-type-Pan\",\n      \"capability-type-Tilt\",\n      \"capability-type-PanTiltSpeed\",\n      \"capability-type-WheelSlot\",\n      \"capability-type-WheelShake\",\n      \"capability-type-WheelRotation\",\n      \"capability-type-Effect\",\n      \"capability-type-Zoom\",\n      \"capability-type-Maintenance\",\n      \"fine-channel-alias\",\n      \"floating-point-weight\",\n      \"multiple-categories\",\n      \"reused-channels\",\n      \"wheel-type-Open\",\n      \"wheel-slot-type-Open\"\n    ]\n  }\n]\n"
  },
  {
    "path": "tests/test-fixtures.md",
    "content": "# Test fixtures\n\nSee the [fixture feature documentation](../docs/fixture-features.md). This file is automatically\ngenerated by [`cli/build-test-fixtures.js`](../cli/build-test-fixtures.js).\n\n1. [*AFX* LMH460Z](../fixtures/afx/lmh460z.json)\n2. [*Astera* FP3 Hyperion Tube](../fixtures/astera/fp3-hyperion-tube.json)\n3. [*Ayrton* Diablo-TC](../fixtures/ayrton/diablo-tc.json)\n4. [*cameo* Auro Beam 150](../fixtures/cameo/auro-beam-150.json)\n5. [*cameo* Auro Spot 400](../fixtures/cameo/auro-spot-400.json)\n6. [*cameo* Hydrabeam 300 RGBW](../fixtures/cameo/hydrabeam-300-rgbw.json)\n7. [*Flash Professional* LED Moving Head 150W](../fixtures/flash-professional/led-moving-head-150w.json)\n8. [*Generic* Pan/Tilt Fader](../fixtures/generic/pan-tilt.json)\n9. [*GLP* impression Laser](../fixtures/glp/impression-laser.json)\n10. [*GLP* KNV Arc](../fixtures/glp/knv-arc.json)\n11. [*Lixada* Mini Moving Head RGBW](../fixtures/lixada/mini-moving-head-rgbw.json)\n12. [*Martin* MAC Axiom Hybrid](../fixtures/martin/mac-axiom-hybrid.json)\n13. [*Martin* MAC Encore Performance](../fixtures/martin/mac-encore-performance.json)\n14. [*Martin* Mania SCX500](../fixtures/martin/mania-scx500.json)\n15. [*MDG* theONE Atmospheric Generator](../fixtures/mdg/theone-atmospheric-generator.json)\n16. [*Prolights* DIAMOND19](../fixtures/prolights/diamond19.json)\n17. [*QTX* Lux Ld01](../fixtures/qtx/lux-ld01.json)\n18. [*Robe* ROBIN Viva CMY](../fixtures/robe/robin-viva-cmy.json)\n19. [*Stairville* MH-x30](../fixtures/stairville/mh-x30.json)\n20. [*Varytec* Hero Spot 230](../fixtures/varytec/hero-spot-230.json)\n21. [*Varytec* Hero Wash 340FX RGBW Zoom](../fixtures/varytec/hero-wash-340fx-rgbw-zoom.json)\n\n*Fixture number* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21\n|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-\n**16bit capability range** [<sup>[1]</sup>](#user-content-footnote-1) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n**16bit default value** [<sup>[2]</sup>](#user-content-footnote-2) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅\n**Capability type NoFunction** [<sup>[3]</sup>](#user-content-footnote-3) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n**Capability type ShutterStrobe** [<sup>[4]</sup>](#user-content-footnote-4) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n**Capability type StrobeSpeed** [<sup>[5]</sup>](#user-content-footnote-5) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type StrobeDuration** [<sup>[6]</sup>](#user-content-footnote-6) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type Intensity** [<sup>[7]</sup>](#user-content-footnote-7) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n**Capability type ColorIntensity** [<sup>[8]</sup>](#user-content-footnote-8) | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅\n**Capability type ColorPreset** [<sup>[9]</sup>](#user-content-footnote-9) | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅\n**Capability type ColorTemperature** [<sup>[10]</sup>](#user-content-footnote-10) | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅\n**Capability type Pan** [<sup>[11]</sup>](#user-content-footnote-11) | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n**Capability type PanContinuous** [<sup>[12]</sup>](#user-content-footnote-12) | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type Tilt** [<sup>[13]</sup>](#user-content-footnote-13) | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n**Capability type TiltContinuous** [<sup>[14]</sup>](#user-content-footnote-14) | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type PanTiltSpeed** [<sup>[15]</sup>](#user-content-footnote-15) | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n*Fixture number* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21\n**Capability type WheelSlot** [<sup>[16]</sup>](#user-content-footnote-16) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅\n**Capability type WheelShake** [<sup>[17]</sup>](#user-content-footnote-17) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅\n**Capability type WheelSlotRotation** [<sup>[18]</sup>](#user-content-footnote-18) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌\n**Capability type WheelRotation** [<sup>[19]</sup>](#user-content-footnote-19) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅\n**Capability type Effect** [<sup>[20]</sup>](#user-content-footnote-20) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅\n**Capability type EffectSpeed** [<sup>[21]</sup>](#user-content-footnote-21) | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌\n**Capability type EffectDuration** [<sup>[22]</sup>](#user-content-footnote-22) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type EffectParameter** [<sup>[23]</sup>](#user-content-footnote-23) | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type SoundSensitivity** [<sup>[24]</sup>](#user-content-footnote-24) | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type BeamAngle** [<sup>[25]</sup>](#user-content-footnote-25) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type BeamPosition** [<sup>[26]</sup>](#user-content-footnote-26) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type Focus** [<sup>[27]</sup>](#user-content-footnote-27) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌\n**Capability type Zoom** [<sup>[28]</sup>](#user-content-footnote-28) | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅\n**Capability type Iris** [<sup>[29]</sup>](#user-content-footnote-29) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n**Capability type IrisEffect** [<sup>[30]</sup>](#user-content-footnote-30) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n*Fixture number* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21\n**Capability type Frost** [<sup>[31]</sup>](#user-content-footnote-31) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n**Capability type FrostEffect** [<sup>[32]</sup>](#user-content-footnote-32) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n**Capability type Prism** [<sup>[33]</sup>](#user-content-footnote-33) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌\n**Capability type PrismRotation** [<sup>[34]</sup>](#user-content-footnote-34) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌\n**Capability type BladeInsertion** [<sup>[35]</sup>](#user-content-footnote-35) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type BladeRotation** [<sup>[36]</sup>](#user-content-footnote-36) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type BladeSystemRotation** [<sup>[37]</sup>](#user-content-footnote-37) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type Fog** [<sup>[38]</sup>](#user-content-footnote-38) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type FogOutput** [<sup>[39]</sup>](#user-content-footnote-39) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type FogType** [<sup>[40]</sup>](#user-content-footnote-40) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type Rotation** [<sup>[41]</sup>](#user-content-footnote-41) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type Speed** [<sup>[42]</sup>](#user-content-footnote-42) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Capability type Time** [<sup>[43]</sup>](#user-content-footnote-43) | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n**Capability type Maintenance** [<sup>[44]</sup>](#user-content-footnote-44) | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅\n**Capability type Generic** [<sup>[45]</sup>](#user-content-footnote-45) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌\n*Fixture number* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21\n**Duplicate channel names** | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌\n**Fine channels (16bit)** [<sup>[46]</sup>](#user-content-footnote-46) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n**Fine channels (>16bit)** [<sup>[47]</sup>](#user-content-footnote-47) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Fine channel capabilities** [<sup>[48]</sup>](#user-content-footnote-48) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n**Fine before coarse** [<sup>[49]</sup>](#user-content-footnote-49) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Fine not-adjacent after coarse** [<sup>[50]</sup>](#user-content-footnote-50) | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Floating point dimensions** [<sup>[51]</sup>](#user-content-footnote-51) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Floating point weight** | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅\n**Floating point power** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌\n**Floating point color temperature** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Floating point lumens** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Floating point lens degrees** | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Many modes** [<sup>[52]</sup>](#user-content-footnote-52) | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Uses pixelKeys** [<sup>[53]</sup>](#user-content-footnote-53) | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌\n**Uses pixelCount** [<sup>[54]</sup>](#user-content-footnote-54) | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n*Fixture number* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21\n**Uses pixelGroups** [<sup>[55]</sup>](#user-content-footnote-55) | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌\n**Uses pixelGroup number constraints** [<sup>[56]</sup>](#user-content-footnote-56) | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Uses pixelGroup string constraints** [<sup>[57]</sup>](#user-content-footnote-57) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌\n**Custom matrix layout** [<sup>[58]</sup>](#user-content-footnote-58) | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌\n**Fine matrix channel** [<sup>[59]</sup>](#user-content-footnote-59) | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Switching matrix channel** [<sup>[60]</sup>](#user-content-footnote-60) | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Matrix channel overridden** [<sup>[61]</sup>](#user-content-footnote-61) | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Matrix channel used directly** [<sup>[62]</sup>](#user-content-footnote-62) | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Multiple categories** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅\n**Multiple Focuses** [<sup>[63]</sup>](#user-content-footnote-63) | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**No physical** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**`null` channels** [<sup>[64]</sup>](#user-content-footnote-64) | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Physical override** [<sup>[65]</sup>](#user-content-footnote-65) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**RDM** [<sup>[66]</sup>](#user-content-footnote-66) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n**Fixture redirect reason FixtureRenamed** [<sup>[67]</sup>](#user-content-footnote-67) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌\n*Fixture number* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21\n**Fixture redirect reason SameAsDifferentBrand** [<sup>[68]</sup>](#user-content-footnote-68) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Reused channels** [<sup>[69]</sup>](#user-content-footnote-69) | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n**Switching channels** [<sup>[70]</sup>](#user-content-footnote-70) | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌\n**Switches fine channels** [<sup>[71]</sup>](#user-content-footnote-71) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌\n**Switching channel at different positions** [<sup>[72]</sup>](#user-content-footnote-72) | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌\n**Wheel type Open** [<sup>[73]</sup>](#user-content-footnote-73) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅\n**Wheel type Closed** [<sup>[74]</sup>](#user-content-footnote-74) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel type Color** [<sup>[75]</sup>](#user-content-footnote-75) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌\n**Wheel type Gobo** [<sup>[76]</sup>](#user-content-footnote-76) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌\n**Wheel type Prism** [<sup>[77]</sup>](#user-content-footnote-77) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel type Iris** [<sup>[78]</sup>](#user-content-footnote-78) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel type Frost** [<sup>[79]</sup>](#user-content-footnote-79) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel type AnimationGobo** [<sup>[80]</sup>](#user-content-footnote-80) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel slot type Open** [<sup>[81]</sup>](#user-content-footnote-81) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅\n**Wheel slot type Closed** [<sup>[82]</sup>](#user-content-footnote-82) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n*Fixture number* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21\n**Wheel slot type Color** [<sup>[83]</sup>](#user-content-footnote-83) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌\n**Wheel slot type Gobo** [<sup>[84]</sup>](#user-content-footnote-84) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌\n**Wheel slot type Prism** [<sup>[85]</sup>](#user-content-footnote-85) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel slot type Iris** [<sup>[86]</sup>](#user-content-footnote-86) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel slot type Frost** [<sup>[87]</sup>](#user-content-footnote-87) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel slot type AnimationGoboStart** [<sup>[88]</sup>](#user-content-footnote-88) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel slot type AnimationGoboEnd** [<sup>[89]</sup>](#user-content-footnote-89) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌\n**Wheel slot uses resource** [<sup>[90]</sup>](#user-content-footnote-90) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌\n\n## Footnotes\n\n**<a id=\"user-content-footnote-1\">[1]</a>**: Whether a capability has a 16bit DMX value range  \n**<a id=\"user-content-footnote-2\">[2]</a>**: Whether a channel has a 16bit default value  \n**<a id=\"user-content-footnote-3\">[3]</a>**: Whether the fixture has at least one capability of type 'NoFunction'  \n**<a id=\"user-content-footnote-4\">[4]</a>**: Whether the fixture has at least one capability of type 'ShutterStrobe'  \n**<a id=\"user-content-footnote-5\">[5]</a>**: Whether the fixture has at least one capability of type 'StrobeSpeed'  \n**<a id=\"user-content-footnote-6\">[6]</a>**: Whether the fixture has at least one capability of type 'StrobeDuration'  \n**<a id=\"user-content-footnote-7\">[7]</a>**: Whether the fixture has at least one capability of type 'Intensity'  \n**<a id=\"user-content-footnote-8\">[8]</a>**: Whether the fixture has at least one capability of type 'ColorIntensity'  \n**<a id=\"user-content-footnote-9\">[9]</a>**: Whether the fixture has at least one capability of type 'ColorPreset'  \n**<a id=\"user-content-footnote-10\">[10]</a>**: Whether the fixture has at least one capability of type 'ColorTemperature'  \n**<a id=\"user-content-footnote-11\">[11]</a>**: Whether the fixture has at least one capability of type 'Pan'  \n**<a id=\"user-content-footnote-12\">[12]</a>**: Whether the fixture has at least one capability of type 'PanContinuous'  \n**<a id=\"user-content-footnote-13\">[13]</a>**: Whether the fixture has at least one capability of type 'Tilt'  \n**<a id=\"user-content-footnote-14\">[14]</a>**: Whether the fixture has at least one capability of type 'TiltContinuous'  \n**<a id=\"user-content-footnote-15\">[15]</a>**: Whether the fixture has at least one capability of type 'PanTiltSpeed'  \n**<a id=\"user-content-footnote-16\">[16]</a>**: Whether the fixture has at least one capability of type 'WheelSlot'  \n**<a id=\"user-content-footnote-17\">[17]</a>**: Whether the fixture has at least one capability of type 'WheelShake'  \n**<a id=\"user-content-footnote-18\">[18]</a>**: Whether the fixture has at least one capability of type 'WheelSlotRotation'  \n**<a id=\"user-content-footnote-19\">[19]</a>**: Whether the fixture has at least one capability of type 'WheelRotation'  \n**<a id=\"user-content-footnote-20\">[20]</a>**: Whether the fixture has at least one capability of type 'Effect'  \n**<a id=\"user-content-footnote-21\">[21]</a>**: Whether the fixture has at least one capability of type 'EffectSpeed'  \n**<a id=\"user-content-footnote-22\">[22]</a>**: Whether the fixture has at least one capability of type 'EffectDuration'  \n**<a id=\"user-content-footnote-23\">[23]</a>**: Whether the fixture has at least one capability of type 'EffectParameter'  \n**<a id=\"user-content-footnote-24\">[24]</a>**: Whether the fixture has at least one capability of type 'SoundSensitivity'  \n**<a id=\"user-content-footnote-25\">[25]</a>**: Whether the fixture has at least one capability of type 'BeamAngle'  \n**<a id=\"user-content-footnote-26\">[26]</a>**: Whether the fixture has at least one capability of type 'BeamPosition'  \n**<a id=\"user-content-footnote-27\">[27]</a>**: Whether the fixture has at least one capability of type 'Focus'  \n**<a id=\"user-content-footnote-28\">[28]</a>**: Whether the fixture has at least one capability of type 'Zoom'  \n**<a id=\"user-content-footnote-29\">[29]</a>**: Whether the fixture has at least one capability of type 'Iris'  \n**<a id=\"user-content-footnote-30\">[30]</a>**: Whether the fixture has at least one capability of type 'IrisEffect'  \n**<a id=\"user-content-footnote-31\">[31]</a>**: Whether the fixture has at least one capability of type 'Frost'  \n**<a id=\"user-content-footnote-32\">[32]</a>**: Whether the fixture has at least one capability of type 'FrostEffect'  \n**<a id=\"user-content-footnote-33\">[33]</a>**: Whether the fixture has at least one capability of type 'Prism'  \n**<a id=\"user-content-footnote-34\">[34]</a>**: Whether the fixture has at least one capability of type 'PrismRotation'  \n**<a id=\"user-content-footnote-35\">[35]</a>**: Whether the fixture has at least one capability of type 'BladeInsertion'  \n**<a id=\"user-content-footnote-36\">[36]</a>**: Whether the fixture has at least one capability of type 'BladeRotation'  \n**<a id=\"user-content-footnote-37\">[37]</a>**: Whether the fixture has at least one capability of type 'BladeSystemRotation'  \n**<a id=\"user-content-footnote-38\">[38]</a>**: Whether the fixture has at least one capability of type 'Fog'  \n**<a id=\"user-content-footnote-39\">[39]</a>**: Whether the fixture has at least one capability of type 'FogOutput'  \n**<a id=\"user-content-footnote-40\">[40]</a>**: Whether the fixture has at least one capability of type 'FogType'  \n**<a id=\"user-content-footnote-41\">[41]</a>**: Whether the fixture has at least one capability of type 'Rotation'  \n**<a id=\"user-content-footnote-42\">[42]</a>**: Whether the fixture has at least one capability of type 'Speed'  \n**<a id=\"user-content-footnote-43\">[43]</a>**: Whether the fixture has at least one capability of type 'Time'  \n**<a id=\"user-content-footnote-44\">[44]</a>**: Whether the fixture has at least one capability of type 'Maintenance'  \n**<a id=\"user-content-footnote-45\">[45]</a>**: Whether the fixture has at least one capability of type 'Generic'  \n**<a id=\"user-content-footnote-46\">[46]</a>**: Whether a channel defines exactly one fine channel alias  \n**<a id=\"user-content-footnote-47\">[47]</a>**: Whether a channel defines two or more fine channel aliases  \n**<a id=\"user-content-footnote-48\">[48]</a>**: Whether a channel with fine channel aliases has capabilities  \n**<a id=\"user-content-footnote-49\">[49]</a>**: Fine channel used in a mode before its coarse channel  \n**<a id=\"user-content-footnote-50\">[50]</a>**: Coarse channel with fine channels are not directly after each other  \n**<a id=\"user-content-footnote-51\">[51]</a>**: In fixture physical or in a mode's physical override. See [#133](https://github.com/OpenLightingProject/open-fixture-library/issues/133).  \n**<a id=\"user-content-footnote-52\">[52]</a>**: True if the fixture has more than 15 modes.  \n**<a id=\"user-content-footnote-53\">[53]</a>**: The fixture has a matrix and has set the pixelKeys individually.  \n**<a id=\"user-content-footnote-54\">[54]</a>**: The fixture has a matrix and has set the pixelCount property.  \n**<a id=\"user-content-footnote-55\">[55]</a>**: The fixture has a matrix and has set pixelGroups.  \n**<a id=\"user-content-footnote-56\">[56]</a>**: The fixture has a matrix and has set pixelGroups using number constraint syntax.  \n**<a id=\"user-content-footnote-57\">[57]</a>**: The fixture has a matrix and has set pixelGroups using string constraint syntax.  \n**<a id=\"user-content-footnote-58\">[58]</a>**: The fixture has a matrix and it uses null pixelKeys – it is no line, rectangle or cube.  \n**<a id=\"user-content-footnote-59\">[59]</a>**: The fixture repeats fine channels for matrix pixels.  \n**<a id=\"user-content-footnote-60\">[60]</a>**: The fixture repeats switching channels for matrix pixels.  \n**<a id=\"user-content-footnote-61\">[61]</a>**: An available channel overrides a specific matrix channel (at a specific pixel).  \n**<a id=\"user-content-footnote-62\">[62]</a>**: If a mode contains a resolved matrix channel key in its raw channel list or if a non-matrix switching channel switches to a matrix channel.  \n**<a id=\"user-content-footnote-63\">[63]</a>**: True if multiple Pan / Tilt channels are used in some mode.  \n**<a id=\"user-content-footnote-64\">[64]</a>**: Channel list of a mode contains null, so it has an unused channel  \n**<a id=\"user-content-footnote-65\">[65]</a>**: Whether at least one mode uses the 'physical' property  \n**<a id=\"user-content-footnote-66\">[66]</a>**: Whether an RDM model ID is set  \n**<a id=\"user-content-footnote-67\">[67]</a>**: Whether the fixture is a fixture redirect with reason 'FixtureRenamed'  \n**<a id=\"user-content-footnote-68\">[68]</a>**: Whether the fixture is a fixture redirect with reason 'SameAsDifferentBrand'  \n**<a id=\"user-content-footnote-69\">[69]</a>**: Whether there is at least one channel that is used in different modes  \n**<a id=\"user-content-footnote-70\">[70]</a>**: Whether at least one channel defines switching channel aliases  \n**<a id=\"user-content-footnote-71\">[71]</a>**: Whether at least one switching channel switches fine channels  \n**<a id=\"user-content-footnote-72\">[72]</a>**: Whether there is a switching channel that is used at different positions in different modes  \n**<a id=\"user-content-footnote-73\">[73]</a>**: Whether the fixture has at least one wheel of type 'Open'  \n**<a id=\"user-content-footnote-74\">[74]</a>**: Whether the fixture has at least one wheel of type 'Closed'  \n**<a id=\"user-content-footnote-75\">[75]</a>**: Whether the fixture has at least one wheel of type 'Color'  \n**<a id=\"user-content-footnote-76\">[76]</a>**: Whether the fixture has at least one wheel of type 'Gobo'  \n**<a id=\"user-content-footnote-77\">[77]</a>**: Whether the fixture has at least one wheel of type 'Prism'  \n**<a id=\"user-content-footnote-78\">[78]</a>**: Whether the fixture has at least one wheel of type 'Iris'  \n**<a id=\"user-content-footnote-79\">[79]</a>**: Whether the fixture has at least one wheel of type 'Frost'  \n**<a id=\"user-content-footnote-80\">[80]</a>**: Whether the fixture has at least one wheel of type 'AnimationGobo'  \n**<a id=\"user-content-footnote-81\">[81]</a>**: Whether the fixture has at least one wheel slot of type 'Open'  \n**<a id=\"user-content-footnote-82\">[82]</a>**: Whether the fixture has at least one wheel slot of type 'Closed'  \n**<a id=\"user-content-footnote-83\">[83]</a>**: Whether the fixture has at least one wheel slot of type 'Color'  \n**<a id=\"user-content-footnote-84\">[84]</a>**: Whether the fixture has at least one wheel slot of type 'Gobo'  \n**<a id=\"user-content-footnote-85\">[85]</a>**: Whether the fixture has at least one wheel slot of type 'Prism'  \n**<a id=\"user-content-footnote-86\">[86]</a>**: Whether the fixture has at least one wheel slot of type 'Iris'  \n**<a id=\"user-content-footnote-87\">[87]</a>**: Whether the fixture has at least one wheel slot of type 'Frost'  \n**<a id=\"user-content-footnote-88\">[88]</a>**: Whether the fixture has at least one wheel slot of type 'AnimationGoboStart'  \n**<a id=\"user-content-footnote-89\">[89]</a>**: Whether the fixture has at least one wheel slot of type 'AnimationGoboEnd'  \n**<a id=\"user-content-footnote-90\">[90]</a>**: Whether the fixture has at least one wheel slot that references a resource  \n"
  },
  {
    "path": "ui/api/download.js",
    "content": "import { fileURLToPath } from 'url';\nimport express from 'express';\nimport JSZip from 'jszip';\nimport importJson from '../../lib/import-json.js';\nimport Fixture from '../../lib/model/Fixture.js';\nimport Manufacturer from '../../lib/model/Manufacturer.js';\nimport { embedResourcesIntoFixtureJson, fixtureFromRepository } from '../../lib/model.js';\nimport { sendAttachment, sendJson } from '../../lib/server-response-helpers.js';\n/** @import { ServerResponse } from 'http' */\n\nconst pluginsPromise = importJson('../../plugins/plugins.json', import.meta.url);\nconst registerPromise = importJson('../../fixtures/register.json', import.meta.url);\n\n/**\n * Instruct Express to initiate a download of one / multiple exported fixture files.\n * @param {ServerResponse} response The Node ServerResponse object.\n * @param {string} pluginKey Key of the export plugin to use.\n * @param {Fixture[]} fixtures Array of fixtures to export.\n * @param {string} zipName Name of the zip file (if multiple files should be downloaded).\n * @param {string} errorDesc String describing what fixture(s) should have been downloaded.\n * @returns {Promise} A Promise that is resolved when the response is sent.\n */\nasync function downloadFixtures(response, pluginKey, fixtures, zipName, errorDesc) {\n  const plugin = await import(`../../plugins/${pluginKey}/export.js`);\n\n  try {\n    const files = await plugin.exportFixtures(fixtures, {\n      baseDirectory: fileURLToPath(new URL('../../', import.meta.url)),\n      date: new Date(),\n    });\n\n    if (files.length === 1) {\n      response.statusCode = 200;\n      sendAttachment(response, files[0]);\n      return;\n    }\n\n    // else zip all together\n    const archive = new JSZip();\n    for (const file of files) {\n      archive.file(file.name, file.content);\n    }\n\n    const zipBuffer = await archive.generateAsync({\n      type: 'nodebuffer',\n      compression: 'DEFLATE',\n    });\n    response.statusCode = 200;\n    sendAttachment(response, {\n      name: `ofl_export_${zipName}.zip`,\n      mimetype: 'application/zip',\n      content: zipBuffer,\n    });\n  }\n  catch (error) {\n    response.statusCode = 500;\n    response.write(`Exporting ${errorDesc} with ${pluginKey} failed: ${error.toString()}`);\n    response.end();\n  }\n}\n\nconst router = express.Router();\n\n// support JSON encoded bodies\nrouter.use(express.json({ limit: '50mb' }));\n\nrouter.get(/^\\/download\\.(?<format>[a-z0-9_.-]+)$/, async (request, response, next) => {\n  const { format } = request.params;\n\n  const plugins = await pluginsPromise;\n  if (!plugins.exportPlugins.includes(format)) {\n    next();\n    return;\n  }\n\n  const register = await registerPromise;\n  const fixtures = await Promise.all(\n    Object.keys(register.filesystem).filter(\n      (fixtureKey) => !('redirectTo' in register.filesystem[fixtureKey]) || register.filesystem[fixtureKey].reason === 'SameAsDifferentBrand',\n    ).map((fixture) => {\n      const [manufacturer, key] = fixture.split('/');\n      return fixtureFromRepository(manufacturer, key);\n    }),\n  );\n\n  downloadFixtures(response, format, fixtures, format, 'all fixtures');\n});\n\nrouter.post(/^\\/download-editor\\.(?<format>[a-z0-9_.-]+)$/, async (request, response) => {\n  const { format } = request.params;\n\n  const plugins = await pluginsPromise;\n  if (!plugins.exportPlugins.includes(format)) {\n    response.statusCode = 500;\n    response.write(`Exporting fixture with ${format} failed: Plugin is not supported.`);\n    response.end();\n\n    return;\n  }\n\n  const outObject = request.body;\n  const fixtures = await Promise.all(Object.entries(outObject.fixtures).map(async ([key, jsonObject]) => {\n    const [manufacturerKey, fixtureKey] = key.split('/');\n\n    const manufacturer = new Manufacturer(manufacturerKey, outObject.manufacturers[manufacturerKey]);\n    await embedResourcesIntoFixtureJson(jsonObject);\n\n    return new Fixture(manufacturer, fixtureKey, jsonObject);\n  }));\n\n  let zipName;\n  let errorDesc;\n  if (fixtures.length === 1) {\n    zipName = `${fixtures[0].manufacturer.key}_${fixtures[0].key}_${format}`;\n    errorDesc = `fixture ${fixtures[0].manufacturer.key}/${fixtures[0].key}`;\n  }\n  else {\n    zipName = format;\n    errorDesc = `${fixtures.length} fixtures`;\n  }\n\n  downloadFixtures(response, format, fixtures, zipName, errorDesc);\n});\n\nrouter.get(/^\\/(?<manufacturerKey>[^/]+)\\/(?<fixtureKey>[^/.]+)\\.(?<format>[a-z0-9_.-]+)$/, async (request, response, next) => {\n  const { manufacturerKey, fixtureKey, format } = request.params;\n\n  const register = await registerPromise;\n  if (!(`${manufacturerKey}/${fixtureKey}` in register.filesystem)) {\n    next();\n    return;\n  }\n\n  if (format === 'json') {\n    try {\n      const json = await importJson(`../../fixtures/${manufacturerKey}/${fixtureKey}.json`, import.meta.url);\n      await embedResourcesIntoFixtureJson(json);\n      sendJson(response, json);\n    }\n    catch (error) {\n      response.statusCode = 500;\n      response.write(`Fetching ${manufacturerKey}/${fixtureKey}.json failed: ${error.toString()}`);\n      response.end();\n    }\n    return;\n  }\n\n  const plugins = await pluginsPromise;\n  if (!plugins.exportPlugins.includes(format)) {\n    next();\n    return;\n  }\n\n  const fixtures = [await fixtureFromRepository(manufacturerKey, fixtureKey)];\n  const zipName = `${manufacturerKey}_${fixtureKey}_${format}`;\n  const errorDesc = `fixture ${manufacturerKey}/${fixtureKey}`;\n\n  downloadFixtures(response, format, fixtures, zipName, errorDesc);\n});\n\nexport default router;\n"
  },
  {
    "path": "ui/api/index.js",
    "content": "import { fileURLToPath } from 'url';\nimport { styleText } from 'util';\nimport cors from 'cors';\nimport express from 'express';\nimport { OpenAPIBackend } from 'openapi-backend';\nimport getAjvErrorMessages from '../../lib/get-ajv-error-messages.js';\nimport { sendJson } from '../../lib/server-response-helpers.js';\nimport * as routeHandlers from './routes.js';\n\n/**\n * @typedef {object} ApiResponse\n * @property {number} [statusCode=200] The HTTP status code set for the response.\n * @property {object} body The response body that should be sent as JSON back to the API client.\n */\n\nconst app = express();\napp.disable('x-powered-by');\n\n// support JSON encoded bodies\napp.use(express.json({ limit: '50mb' }));\n\nconst corsWhitelist = [\n  /[./]open-fixture-library\\.org(?::\\d+|)$/,\n  /\\/localhost(?::\\d+|)$/,\n];\n\napp.use(cors({\n  origin(origin, callback) {\n    const corsAllowed = process.env.NODE_ENV !== 'production'\n      || !origin // allow non XHR/fetch requests\n      || corsWhitelist.some((regex) => regex.test(origin));\n\n    callback(null, corsAllowed ? true : 'https://open-fixture-library.org');\n  },\n  optionsSuccessStatus: 200, // IE11 chokes on default 204\n}));\n\nconst base64Regex = /^(?:[\\d+/A-Za-z]{4})*(?:[\\d+/A-Za-z]{2}==|[\\d+/A-Za-z]{3}=)?$/;\n\nconst api = new OpenAPIBackend({\n  definition: fileURLToPath(new URL('openapi.json', import.meta.url)),\n  strict: process.env.NODE_ENV !== 'production',\n  ajvOpts: {\n    formats: {\n      base64: base64Regex,\n    },\n  },\n  handlers: {\n    ...routeHandlers,\n    validationFail({ validation, request, operation }) {\n      let error = validation.errors;\n\n      if (typeof error !== 'string') {\n        error = getAjvErrorMessages(Array.isArray(error) ? error : [error], 'request').join(',\\n');\n      }\n\n      const errorDescription = `API request for ${request.originalUrl} (${operation.operationId}) doesn't match schema:`;\n\n      console.error(styleText('bgRed', errorDescription));\n      console.error(error);\n\n      return {\n        statusCode: 400,\n        body: { error: `${errorDescription}\\n${error}` },\n      };\n    },\n    notFound(context) {\n      return {\n        statusCode: 404,\n        body: { error: 'Not found' },\n      };\n    },\n    methodNotAllowed(context) {\n      return {\n        statusCode: 405,\n        body: { error: 'Method not allowed' },\n      };\n    },\n    notImplemented(context) {\n      return {\n        statusCode: 501,\n        body: { error: 'No handler registered for operation' },\n      };\n    },\n    postResponseHandler({ request, response, operation }) {\n      if (!response || !operation) {\n        return null;\n      }\n\n      const { statusCode = 200, body } = /** @type {ApiResponse} */ response;\n\n      // validate API responses in development mode\n      if (process.env.NODE_ENV !== 'production') {\n        const valid = api.validateResponse(body, operation, statusCode);\n\n        if (valid.errors) {\n          let error = valid.errors;\n\n          if (typeof error !== 'string') {\n            error = getAjvErrorMessages(Array.isArray(error) ? error : [error], 'response').join(',\\n');\n          }\n\n          const errorDescription = `API response for ${request.originalUrl} (${operation.operationId}, status code ${statusCode}) doesn't match schema:`;\n\n          console.error(styleText('bgRed', errorDescription));\n          console.error(error);\n        }\n      }\n\n      return response;\n    },\n  },\n});\n\napp.use(async (request, response) => {\n  const { statusCode = 200, body } = await api.handleRequest(request);\n  response.statusCode = statusCode;\n  sendJson(response, body);\n});\n\nexport default app;\n"
  },
  {
    "path": "ui/api/openapi.json",
    "content": "{\n  \"openapi\": \"3.0.2\",\n  \"info\": {\n    \"title\": \"Open Fixture Library API\",\n    \"version\": \"1.0\"\n  },\n  \"servers\": [\n    {\n      \"url\": \"https://open-fixture-library.org/api/v1\"\n    },\n    {\n      \"url\": \"http://localhost:3000/api/v1\"\n    }\n  ],\n  \"paths\": {\n    \"/get-search-results\": {\n      \"$ref\": \"routes/get-search-results.json\"\n    },\n    \"/submit-feedback\": {\n      \"$ref\": \"routes/submit-feedback.json\"\n    },\n    \"/fixtures/from-editor\": {\n      \"$ref\": \"routes/fixtures/from-editor.json\"\n    },\n    \"/fixtures/import\": {\n      \"$ref\": \"routes/fixtures/import.json\"\n    },\n    \"/fixtures/submit\": {\n      \"$ref\": \"routes/fixtures/submit.json\"\n    },\n    \"/manufacturers\": {\n      \"$ref\": \"routes/manufacturers/index.json\"\n    },\n    \"/manufacturers/{manufacturerKey}\": {\n      \"$ref\": \"routes/manufacturers/_manufacturerKey.json\"\n    },\n    \"/plugins\": {\n      \"$ref\": \"routes/plugins/index.json\"\n    },\n    \"/plugins/{pluginKey}\": {\n      \"$ref\": \"routes/plugins/_pluginKey.json\"\n    }\n  },\n  \"components\": {\n    \"schemas\": {\n      \"FixtureCreateResult\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"manufacturers\": {\n            \"type\": \"object\"\n          },\n          \"fixtures\": {\n            \"type\": \"object\"\n          },\n          \"warnings\": {\n            \"type\": \"object\"\n          },\n          \"errors\": {\n            \"type\": \"object\"\n          }\n        },\n        \"required\": [\n          \"manufacturers\",\n          \"fixtures\",\n          \"warnings\",\n          \"errors\"\n        ],\n        \"additionalProperties\": false,\n        \"example\": {\n          \"manufacturers\": {\n            \"man-key\": {\n              \"name\": \"Manufacturer name\",\n              \"website\": \"https://example.org\"\n            }\n          },\n          \"fixtures\": {\n            \"man-key/fix-key\": {\n              \"name\": \"Fixture name\",\n              \"$comment\": \"…\"\n            }\n          },\n          \"warnings\": {\n            \"man-key/fix-key\": [\n              \"Some warning for fixture man-key/fix-key.\"\n            ]\n          },\n          \"errors\": {\n            \"man-key/fix-key\": []\n          }\n        }\n      },\n      \"Error\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"error\": {\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\"error\"],\n        \"additionalProperties\": false,\n        \"example\": {\n          \"error\": \"Some error message.\"\n        }\n      }\n    },\n    \"responses\": {\n      \"201-FixtureCreateResult\": {\n        \"description\": \"Fixture successfully imported\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/FixtureCreateResult\"\n            }\n          }\n        }\n      },\n      \"400-BadRequestError\": {\n        \"description\": \"Bad request\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            }\n          }\n        }\n      },\n      \"404-NotFoundError\": {\n        \"description\": \"Not Found\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/fixtures/from-editor.js",
    "content": "import importJson from '../../../../lib/import-json.js';\nimport CoarseChannel from '../../../../lib/model/CoarseChannel.js';\nimport {\n  capabilityTypes,\n  channelProperties,\n  fixtureProperties,\n  linksProperties,\n  modeProperties,\n  physicalProperties,\n  wheelSlotTypes,\n} from '../../../../lib/schema-properties.js';\nimport { checkFixture } from '../../../../tests/fixture-valid.js';\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../../index.js' */\n/** @import { FixtureCreateResult } from '../../../../lib/types.js' */\n\n/**\n * Converts the given editor fixture data into OFL fixtures and responds with a FixtureCreateResult.\n * @param {OpenApiBackendContext} ctx Passed from OpenAPI Backend.\n * @returns {Promise<ApiResponse>} The handled response.\n */\nexport async function createFixtureFromEditor({ request }) {\n  try {\n    const fixtureCreateResult = await getFixtureCreateResult(request.requestBody);\n    return {\n      statusCode: 201,\n      body: fixtureCreateResult,\n    };\n  }\n  catch (error) {\n    return {\n      statusCode: 400,\n      body: {\n        error: error.message,\n      },\n    };\n  }\n}\n\n/**\n * @param {object[]} fixtures The raw fixture data from the Fixture Editor.\n * @returns {Promise<FixtureCreateResult>} A Promise that resolves to the created OFL fixtures (and manufacturers) with warnings and errors.\n */\nasync function getFixtureCreateResult(fixtures) {\n  const result = {\n    manufacturers: {},\n    fixtures: {},\n    warnings: {},\n    errors: {},\n  };\n\n  const manufacturers = await importJson('../../../../fixtures/manufacturers.json', import.meta.url);\n\n  // { 'uuid 1': 'new channel key 1', ... }\n  const channelKeyMapping = {};\n\n  await Promise.all(fixtures.map((fixture) => addFixture(fixture)));\n\n  return result;\n\n  /**\n   * @param {object} fixture The editor fixture object.\n   */\n  async function addFixture(fixture) {\n    const manufacturerKey = getManufacturerKey(fixture);\n    const fixtureKey = getFixtureKey(fixture, manufacturerKey);\n    const key = `${manufacturerKey}/${fixtureKey}`;\n\n    result.fixtures[key] = {\n      $schema: 'https://raw.githubusercontent.com/OpenLightingProject/open-fixture-library/master/schemas/fixture.json',\n    };\n\n    for (const property of Object.keys(fixtureProperties)) {\n      switch (property) {\n        case 'physical': {\n          const physical = getPhysical(fixture.physical);\n          if (!isEmptyObject(physical)) {\n            result.fixtures[key].physical = physical;\n          }\n          break;\n        }\n        case 'meta': {\n          const now = new Date().toISOString().replace(/T.*/, '');\n\n          result.fixtures[key].meta = {\n            authors: [fixture.metaAuthor],\n            createDate: now,\n            lastModifyDate: now,\n          };\n          break;\n        }\n        case 'links': {\n          addLinks(result.fixtures[key], fixture.links);\n          break;\n        }\n        case 'availableChannels': {\n          result.fixtures[key].availableChannels = {};\n          for (const channelId of Object.keys(fixture.availableChannels)) {\n            addAvailableChannel(key, fixture.availableChannels, channelId);\n          }\n          break;\n        }\n        default: {\n          if (property === 'rdm' && propertyExistsIn('rdmModelId', fixture)) {\n            result.fixtures[key].rdm = {\n              modelId: fixture.rdmModelId,\n            };\n            if (propertyExistsIn('rdmSoftwareVersion', fixture)) {\n              result.fixtures[key].rdm.softwareVersion = fixture.rdmSoftwareVersion;\n            }\n          }\n          else if (property === 'modes') {\n            result.fixtures[key].modes = [];\n            for (const mode of fixture.modes) {\n              addMode(key, mode);\n            }\n          }\n          else if (property === 'wheels') {\n            addWheels(result.fixtures[key], fixture);\n          }\n          else if (propertyExistsIn(property, fixture)) {\n            result.fixtures[key][property] = fixture[property];\n          }\n        }\n      }\n    }\n\n    const checkResult = await checkFixture(manufacturerKey, fixtureKey, result.fixtures[key]);\n\n    result.warnings[key] = checkResult.warnings;\n    result.errors[key] = checkResult.errors;\n  }\n\n  /**\n   * If a new manufacturer was entered in the editor, it is also saved here.\n   * @param {object} fixture The editor fixture object.\n   * @returns {string} The manufacturer key.\n   */\n  function getManufacturerKey(fixture) {\n    if (fixture.useExistingManufacturer) {\n      result.manufacturers[fixture.manufacturerKey] = manufacturers[fixture.manufacturerKey];\n      return fixture.manufacturerKey;\n    }\n\n    // add new manufacturer\n    const manufacturerKey = slugify(fixture.newManufacturerName);\n\n    result.manufacturers[manufacturerKey] = {\n      name: fixture.newManufacturerName,\n    };\n\n    if (propertyExistsIn('newManufacturerComment', fixture)) {\n      result.manufacturers[manufacturerKey].comment = fixture.newManufacturerComment;\n    }\n\n    if (propertyExistsIn('newManufacturerWebsite', fixture)) {\n      result.manufacturers[manufacturerKey].website = fixture.newManufacturerWebsite;\n    }\n\n    if (propertyExistsIn('newManufacturerRdmId', fixture)) {\n      result.manufacturers[manufacturerKey].rdmId = fixture.newManufacturerRdmId;\n    }\n\n    return manufacturerKey;\n  }\n\n  /**\n   * @param {object} fixture The editor fixture object.\n   * @param {string} manufacturerKey The manufacturer key of the fixture.\n   * @returns {string} The fixture key.\n   */\n  function getFixtureKey(fixture, manufacturerKey) {\n    if ('key' in fixture && fixture.key !== '[new]') {\n      return fixture.key;\n    }\n\n    let fixtureKey = slugify(fixture.name);\n\n    const otherFixtureKeys = new Set(Object.keys(result.fixtures).filter(\n      (key) => key.startsWith(manufacturerKey),\n    ).map((key) => key.slice(manufacturerKey.length + 1)));\n\n    while (otherFixtureKeys.has(fixtureKey)) {\n      fixtureKey += '-2';\n    }\n\n    return fixtureKey;\n  }\n\n  /**\n   * @param {object} from The editor physical object.\n   * @returns {object} The OFL physical object.\n   */\n  function getPhysical(from) {\n    const physical = {};\n\n    for (const property of Object.keys(physicalProperties)) {\n      if (physicalProperties[property].type === 'object') {\n        physical[property] = {};\n\n        for (const subProperty of Object.keys(physicalProperties[property].properties)) {\n          if (propertyExistsIn(subProperty, from[property])) {\n            physical[property][subProperty] = getComboboxInput(subProperty, from[property]);\n          }\n        }\n\n        if (isEmptyObject(physical[property])) {\n          delete physical[property];\n        }\n      }\n      else if (propertyExistsIn(property, from)) {\n        physical[property] = getComboboxInput(property, from);\n      }\n    }\n\n    return physical;\n  }\n\n  /**\n   * @param {object} fixture The OFL fixture object to save the links to.\n   * @param {object[]} editorLinksArray The editor link object array.\n   */\n  function addLinks(fixture, editorLinksArray) {\n    fixture.links = {};\n\n    const resolveShortenedYouTubeUrl = (url) => {\n      if (url.startsWith('https://youtu.be/')) {\n        const urlObject = new URL(url);\n\n        const videoId = urlObject.pathname.slice(1);\n        const queryParameters = [['v', videoId], ...urlObject.searchParams];\n        const queryParameterString = new URLSearchParams(Object.fromEntries(queryParameters));\n\n        urlObject.host = 'www.youtube.com';\n        urlObject.pathname = 'watch';\n        urlObject.search = `?${queryParameterString}`;\n\n        return urlObject.toString();\n      }\n\n      return url;\n    };\n\n    const linkTypes = Object.keys(linksProperties);\n\n    for (const linkType of linkTypes) {\n      const linksOfType = editorLinksArray\n        .filter(({ type }) => type === linkType)\n        .map(({ url }) => resolveShortenedYouTubeUrl(url));\n\n      if (linksOfType.length > 0) {\n        fixture.links[linkType] = linksOfType;\n      }\n    }\n  }\n\n  /**\n   * Sanitize and save wheels from the editor's channel objects, if there are any.\n   * @param {object} fixture The OFL fixture object to save the wheels to.\n   * @param {object} editorFixture The editor fixture object to get the wheels from.\n   */\n  function addWheels(fixture, editorFixture) {\n    const editorWheelChannels = Object.values(editorFixture.availableChannels).filter(\n      (editorChannel) => editorChannel.wheel && editorChannel.wheel.slots.some(\n        (editorWheelSlot) => editorWheelSlot !== null && editorWheelSlot.type !== '',\n      ),\n    );\n\n    if (editorWheelChannels.length === 0) {\n      return;\n    }\n\n    fixture.wheels = {};\n\n    for (const editorChannel of editorWheelChannels) {\n      const slots = editorChannel.wheel.slots.map((editorWheelSlot) => {\n        if (editorWheelSlot === null || editorWheelSlot.type === '') {\n          return null;\n        }\n\n        const wheelSlot = {\n          type: editorWheelSlot.type,\n        };\n\n        const wheelSlotSchema = wheelSlotTypes[wheelSlot.type];\n\n        for (const slotProperty of Object.keys(wheelSlotSchema.properties)) {\n          if (propertyExistsIn(slotProperty, editorWheelSlot.typeData)) {\n            wheelSlot[slotProperty] = editorWheelSlot.typeData[slotProperty];\n          }\n        }\n\n        return wheelSlot;\n      });\n\n      // remove trailing null slots\n      while (slots.at(-1) === null) {\n        slots.pop();\n      }\n\n      fixture.wheels[editorChannel.name] = {\n        slots,\n      };\n    }\n  }\n\n  /**\n   * @param {string} fixtureKey The key of the fixture to add the channel to.\n   * @param {object} availableChannels All available channels of the editor fixture.\n   * @param {string} channelId The UUID of the channel to add.\n   */\n  function addAvailableChannel(fixtureKey, availableChannels, channelId) {\n    const from = availableChannels[channelId];\n\n    if ('coarseChannelId' in from) {\n      // we already handled this fine channel with its coarse channel\n      return;\n    }\n\n    const channel = {};\n\n    for (const property of Object.keys(channelProperties)) {\n      if (property === 'capabilities') {\n        const capabilities = getCapabilities(from);\n\n        if (capabilities.length === 1) {\n          delete capabilities[0].dmxRange;\n          channel.capability = capabilities[0];\n        }\n        else {\n          channel.capabilities = capabilities;\n        }\n      }\n      else if (property === 'fineChannelAliases' && from.resolution > CoarseChannel.RESOLUTION_8BIT) {\n        channel.fineChannelAliases = [];\n      }\n      else if (property === 'dmxValueResolution') {\n        if (from.resolution !== from.dmxValueResolution && from.capabilities.length > 1) {\n          channel.dmxValueResolution = `${from.dmxValueResolution * 8}bit`;\n        }\n      }\n      else if (propertyExistsIn(property, from)) {\n        channel[property] = getComboboxInput(property, from);\n      }\n    }\n\n    const channelKey = getChannelKey(channel, fixtureKey);\n\n    if ('fineChannelAliases' in channel) {\n      // find all referencing fine channels\n      for (const otherChannel of Object.values(availableChannels)) {\n        if ('coarseChannelId' in otherChannel && otherChannel.coarseChannelId === channelId) {\n          const alias = getFineChannelAlias(channelKey, otherChannel.resolution);\n          channel.fineChannelAliases[otherChannel.resolution - 2] = alias;\n          channelKeyMapping[otherChannel.uuid] = alias;\n        }\n      }\n    }\n\n    if (channel.name === channelKey) {\n      delete channel.name;\n    }\n\n    channelKeyMapping[from.uuid] = channelKey;\n    result.fixtures[fixtureKey].availableChannels[channelKey] = channel;\n  }\n\n  /**\n   * @param {object} channel The OFL channel object.\n   * @param {string} fixtureKey The key of the fixture the channel belongs to.\n   * @returns {string} A unique channel key for the fixture.\n   */\n  function getChannelKey(channel, fixtureKey) {\n    let channelKey = channel.name;\n    const availableChannelKeys = Object.keys(result.fixtures[fixtureKey].availableChannels);\n\n    if (availableChannelKeys.includes(channelKey)) {\n      let appendNumber = 2;\n      while (availableChannelKeys.includes(`${channelKey} ${appendNumber}`)) {\n        appendNumber++;\n      }\n      channelKey = `${channelKey} ${appendNumber}`;\n    }\n\n    return channelKey;\n  }\n\n  /**\n   * @param {string} channelKey The key of the coarse channel.\n   * @param {number} resolution The resolution of the fine channel.\n   * @returns {string} The fine channel alias.\n   */\n  function getFineChannelAlias(channelKey, resolution) {\n    const suffix = resolution > CoarseChannel.RESOLUTION_16BIT ? `^${resolution - 1}` : '';\n    return `${channelKey} fine${suffix}`;\n  }\n\n  /**\n   * @param {object} channel The editor channel object.\n   * @returns {object[]} The OFL capability objects.\n   */\n  function getCapabilities(channel) {\n    return channel.capabilities.map((editorCapability) => {\n      const capability = {};\n\n      const capabilitySchema = capabilityTypes[editorCapability.type];\n\n      for (const capabilityProperty of Object.keys(capabilitySchema.properties)) {\n        if (propertyExistsIn(capabilityProperty, editorCapability)) {\n          capability[capabilityProperty] = editorCapability[capabilityProperty];\n        }\n        else if (propertyExistsIn(capabilityProperty, editorCapability.typeData)) {\n          capability[capabilityProperty] = editorCapability.typeData[capabilityProperty];\n        }\n      }\n\n      if (capability.brightnessStart === 'off' && capability.brightnessEnd === 'bright') {\n        delete capability.brightnessStart;\n        delete capability.brightnessEnd;\n      }\n\n      return capability;\n    });\n  }\n\n  /**\n   * @param {string} fixtureKey The key of the fixture to add the mode to.\n   * @param {object} from The editor mode object.\n   */\n  function addMode(fixtureKey, from) {\n    const mode = {};\n\n    for (const property of Object.keys(modeProperties)) {\n      if (property === 'physical') {\n        const physical = getPhysical(from.physical);\n        if (!isEmptyObject(physical)) {\n          mode.physical = physical;\n        }\n      }\n      else if (property === 'channels') {\n        mode.channels = from.channels.map((uuid) => channelKeyMapping[uuid]);\n      }\n      else if (propertyExistsIn(property, from)) {\n        mode[property] = from[property];\n      }\n    }\n\n    result.fixtures[fixtureKey].modes.push(mode);\n  }\n}\n\n// helper functions\n\n/**\n * @param {object | null} object The object to check.\n * @returns {boolean} Whether the given object literal has no own properties, i.e. that its JSON equivalent is '{}'\n */\nfunction isEmptyObject(object) {\n  return JSON.stringify(object) === '{}';\n}\n\n/**\n * @param {string} property The property key to check.\n * @param {object | null} object The object to check. If it's null, false is returned.\n * @returns {boolean} Whether the given property key is present in the object and its value is non-null and non-empty.\n */\nfunction propertyExistsIn(property, object) {\n  const objectValid = object !== undefined && object !== null;\n  return objectValid && object[property] !== undefined && object[property] !== null && object[property] !== '';\n}\n\n/**\n * @param {string} property The property key to get the value for.\n * @param {object} from The editor object to get the value from.\n * @returns {string} The value from the combobox input, preferring any newly added value.\n */\nfunction getComboboxInput(property, from) {\n  return (from[property] === '[add-value]' && from[`${property}New`] !== '') ? from[`${property}New`] : from[property];\n}\n\n/**\n * @param {string} string The string to slugify.\n * @returns {string} A slugified version of the string, i.e. only containing lowercase letters, numbers and dashes.\n */\nfunction slugify(string) {\n  return string.toLowerCase().replaceAll(/[^\\da-z-]+/g, ' ').trim().replaceAll(/\\s+/g, '-');\n}\n"
  },
  {
    "path": "ui/api/routes/fixtures/from-editor.json",
    "content": "{\n  \"post\": {\n    \"operationId\": \"createFixtureFromEditor\",\n    \"description\": \"Converts the given editor fixture data into OFL fixtures and responds with a FixtureCreateResult.\",\n    \"tags\": [\"fixtures\"],\n    \"requestBody\": {\n      \"required\": true,\n      \"content\": {\n        \"application/json\": {\n          \"schema\": {\n            \"type\": \"array\",\n            \"items\": {\n              \"type\": \"object\",\n              \"description\": \"Fixture object used in the Fixture Editor\"\n            }\n          }\n        }\n      }\n    },\n    \"responses\": {\n      \"201\": {\n        \"$ref\": \"../../openapi.json#/components/responses/201-FixtureCreateResult\"\n      },\n      \"400\": {\n        \"$ref\": \"../../openapi.json#/components/responses/400-BadRequestError\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/fixtures/import.js",
    "content": "import importJson from '../../../../lib/import-json.js';\nimport { checkFixture } from '../../../../tests/fixture-valid.js';\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../../index.js' */\n/** @import { FixtureCreateResult } from '../../../../lib/types.js' */\n\n/**\n * @typedef {object} RequestBody\n * @property {string} plugin Import plugin key.\n * @property {string} fileName Imported file's name.\n * @property {string} fileContentBase64 Imported file's content, as base64 encoded string.\n * @property {string} author Author's name.\n */\n\n/**\n * Imports the uploaded fixture file and responds with a FixtureCreateResult.\n * @param {OpenApiBackendContext} ctx Passed from OpenAPI Backend.\n * @returns {ApiResponse} The handled response.\n */\nexport async function importFixtureFile({ request }) {\n  try {\n    const fixtureCreateResult = await importFixture(request.requestBody);\n    return {\n      statusCode: 201,\n      body: fixtureCreateResult,\n    };\n  }\n  catch (error) {\n    return {\n      statusCode: 400,\n      body: {\n        error: error.message,\n      },\n    };\n  }\n}\n\n/**\n * @param {RequestBody} body The JSON request body.\n * @returns {FixtureCreateResult} The imported fixtures (and manufacturers) with warnings and errors.\n */\nasync function importFixture(body) {\n  const { importPlugins } = await importJson('../../../../plugins/plugins.json', import.meta.url);\n\n  if (!body.plugin || !importPlugins.includes(body.plugin)) {\n    throw new Error(`'${body.plugin}' is not a valid import plugin.`);\n  }\n\n  const plugin = await import(`../../../../plugins/${body.plugin}/import.js`);\n  const { manufacturers, fixtures, warnings } = await plugin.importFixtures(\n    Buffer.from(body.fileContentBase64, 'base64'),\n    body.fileName,\n    body.author,\n  ).catch((parseError) => {\n    parseError.message = `Parse error (${parseError.message})`;\n    throw parseError;\n  });\n\n  /** @type {FixtureCreateResult} */\n  const result = {\n    manufacturers,\n    fixtures,\n    warnings,\n    errors: {},\n  };\n\n  const oflManufacturers = await importJson('../../../../fixtures/manufacturers.json', import.meta.url);\n\n  for (const [key, fixture] of Object.entries(result.fixtures)) {\n    const [manufacturerKey, fixtureKey] = key.split('/');\n\n    const checkResult = await checkFixture(manufacturerKey, fixtureKey, fixture);\n\n    if (!(manufacturerKey in result.manufacturers)) {\n      result.manufacturers[manufacturerKey] = oflManufacturers[manufacturerKey];\n    }\n\n    result.warnings[key] = [...result.warnings[key], ...checkResult.warnings];\n    result.errors[key] = checkResult.errors;\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "ui/api/routes/fixtures/import.json",
    "content": "{\n  \"post\": {\n    \"operationId\": \"importFixtureFile\",\n    \"description\": \"Imports the uploaded fixture file and responds with a FixtureCreateResult.\",\n    \"tags\": [\"fixtures\"],\n    \"requestBody\": {\n      \"required\": true,\n      \"content\": {\n        \"application/json\": {\n          \"schema\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"plugin\": {\n                \"type\": \"string\"\n              },\n              \"fileName\": {\n                \"type\": \"string\"\n              },\n              \"fileContentBase64\": {\n                \"type\": \"string\",\n                \"format\": \"base64\"\n              },\n              \"author\": {\n                \"type\": \"string\"\n              }\n            },\n            \"required\": [\n              \"plugin\",\n              \"fileName\",\n              \"fileContentBase64\",\n              \"author\"\n            ],\n            \"additionalProperties\": false\n          }\n        }\n      }\n    },\n    \"responses\": {\n      \"201\": {\n        \"$ref\": \"../../openapi.json#/components/responses/201-FixtureCreateResult\"\n      },\n      \"400\": {\n        \"$ref\": \"../../openapi.json#/components/responses/400-BadRequestError\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/fixtures/submit.js",
    "content": "import createPullRequest from '../../../../lib/create-github-pr.js';\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../../index.js' */\n/** @import { FixtureCreateResult } from '../../../../lib/types.js' */\n\n/**\n * @typedef {object} RequestBody\n * @property {FixtureCreateResult} fixtureCreateResult The fixtures (and manufacturers) with warnings and errors, to submit.\n * @property {string} githubUsername Author's GitHub username\n * @property {string} githubComment Author's comment.\n */\n\n/**\n * Creates a GitHub pull request with the given fixture data.\n * Includes warnings, errors, GitHub username and GitHub comment in the PR description.\n * @param {OpenApiBackendContext} ctx Passed from OpenAPI Backend.\n * @returns {ApiResponse} The handled response.\n */\nexport async function submitFixtures({ request }) {\n  try {\n    const pullRequestUrl = await createPullRequest(\n      request.requestBody.fixtureCreateResult,\n      request.requestBody.githubUsername,\n      request.requestBody.githubComment,\n    );\n    return {\n      statusCode: 201,\n      body: {\n        pullRequestUrl,\n      },\n    };\n  }\n  catch (error) {\n    return {\n      statusCode: 500,\n      body: {\n        error: `${error.toString()}\\n${error.stack}`,\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/fixtures/submit.json",
    "content": "{\n  \"post\": {\n    \"operationId\": \"submitFixtures\",\n    \"description\": \"Creates a GitHub pull request with the given fixture data. Includes warnings, errors, GitHub username and GitHub comment in the PR description.\",\n    \"tags\": [\"fixtures\"],\n    \"requestBody\": {\n      \"required\": true,\n      \"content\": {\n        \"application/json\": {\n          \"schema\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"fixtureCreateResult\": {\n                \"$ref\": \"../../openapi.json#/components/schemas/FixtureCreateResult\"\n              },\n              \"githubUsername\": {\n                \"type\": \"string\",\n                \"nullable\": true\n              },\n              \"githubComment\": {\n                \"type\": \"string\",\n                \"nullable\": true\n              }\n            },\n            \"required\": [\n              \"fixtureCreateResult\",\n              \"githubUsername\",\n              \"githubComment\"\n            ],\n            \"additionalProperties\": false\n          }\n        }\n      }\n    },\n    \"responses\": {\n      \"201\": {\n        \"description\": \"OK\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"pullRequestUrl\": {\n                  \"type\": \"string\"\n                }\n              },\n              \"required\": [\"pullRequestUrl\"],\n              \"additionalProperties\": false\n            }\n          }\n        }\n      },\n      \"400\": {\n        \"$ref\": \"../../openapi.json#/components/responses/400-BadRequestError\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/get-search-results.js",
    "content": "import importJson from '../../../lib/import-json.js';\n\nlet register;\nlet manufacturers;\n\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../index.js' */\n\n/**\n * Return search results for given parameters. Very primitive match algorithm, maybe put more effort into it sometime.\n * @param {OpenApiBackendContext} ctx Passed from OpenAPI Backend.\n * @returns {Promise<ApiResponse>} The handled response.\n */\nexport async function getSearchResults({ request }) {\n  const { searchQuery, manufacturersQuery, categoriesQuery } = request.requestBody;\n\n  register = await importJson('../../../fixtures/register.json', import.meta.url);\n  manufacturers = await importJson('../../../fixtures/manufacturers.json', import.meta.url);\n\n  const results = Object.keys(register.filesystem).filter(\n    (key) => queryMatch(searchQuery, key) && manufacturerMatch(manufacturersQuery, key) && categoryMatch(categoriesQuery, key),\n  );\n  return {\n    body: results,\n  };\n}\n\n/**\n * Test if a fixture matches the search query.\n * @param {string} searchQuery Search query that the user entered.\n * @param {string} fixtureKey Key of the fixture to test.\n * @returns {boolean} True if the fixture matches the search query, false otherwise.\n */\nfunction queryMatch(searchQuery, fixtureKey) {\n  const manufacturer = fixtureKey.split('/')[0];\n  const fixtureData = register.filesystem[fixtureKey];\n\n  return fixtureKey.includes(searchQuery.toLowerCase()) || `${manufacturers[manufacturer].name} ${fixtureData.name}`.toLowerCase().includes(searchQuery.toLowerCase());\n}\n\n/**\n * Test if a fixture matches the manufacturer query.\n * @param {string[]} manufacturersQuery Selected manufacturers.\n * @param {string} fixtureKey Key of the fixture to test.\n * @returns {boolean} True if the fixture matches the manufacturer query, false otherwise.\n */\nfunction manufacturerMatch(manufacturersQuery, fixtureKey) {\n  const manufacturer = fixtureKey.split('/')[0];\n\n  return (\n    manufacturersQuery.length === 0\n    || (manufacturersQuery.length === 1 && manufacturersQuery[0] === '')\n    || manufacturersQuery.includes(manufacturer)\n  );\n}\n\n/**\n * Test if a fixture matches the category query.\n * @param {string[]} categoriesQuery Selected categories.\n * @param {string} fixtureKey Key of the fixture to test.\n * @returns {boolean} True if the fixture matches the category query, false otherwise.\n */\nfunction categoryMatch(categoriesQuery, fixtureKey) {\n  return (\n    categoriesQuery.length === 0\n    || (categoriesQuery.length === 1 && categoriesQuery[0] === '')\n    || categoriesQuery.some(\n      (category) => register.categories[category]?.includes(fixtureKey),\n    )\n  );\n}\n"
  },
  {
    "path": "ui/api/routes/get-search-results.json",
    "content": "{\n  \"post\": {\n    \"operationId\": \"getSearchResults\",\n    \"description\": \"Return search results for given parameters.\",\n    \"tags\": [\"root\"],\n    \"requestBody\": {\n      \"required\": true,\n      \"content\": {\n        \"application/json\": {\n          \"schema\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"searchQuery\": {\n                \"type\": \"string\"\n              },\n              \"manufacturersQuery\": {\n                \"type\": \"array\",\n                \"items\": {\n                  \"type\": \"string\"\n                }\n              },\n              \"categoriesQuery\": {\n                \"type\": \"array\",\n                \"items\": {\n                  \"type\": \"string\"\n                }\n              }\n            },\n            \"required\": [\n              \"searchQuery\",\n              \"manufacturersQuery\",\n              \"categoriesQuery\"\n            ],\n            \"additionalProperties\": false\n          },\n          \"example\": {\n            \"searchQuery\": \"showtec phantom\",\n            \"manufacturersQuery\": [],\n            \"categoriesQuery\": []\n          }\n        }\n      }\n    },\n    \"responses\": {\n      \"200\": {\n        \"description\": \"Fixture keys matching the queries.\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"example\": [\n              \"showtec/phantom-3r-beam\",\n              \"showtec/phantom-50-led-spot\",\n              \"showtec/phantom-140-led-spot\",\n              \"showtec/phantom-matrix-fx\"\n            ]\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/manufacturers/_manufacturerKey.js",
    "content": "import importJson from '../../../../lib/import-json.js';\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../../index.js' */\n\n/**\n * Returns information about a specific manufacturer.\n * @param {OpenApiBackendContext} ctx Passed from OpenAPI Backend.\n * @returns {Promise<ApiResponse>} The handled response.\n */\nexport async function getManufacturerByKey({ request }) {\n  const { manufacturerKey } = request.params;\n\n  const manufacturers = await importJson('../../../../fixtures/manufacturers.json', import.meta.url);\n  if (!(manufacturerKey in manufacturers) || manufacturerKey === '$schema') {\n    return {\n      statusCode: 404,\n      body: {\n        error: 'Manufacturer not found',\n      },\n    };\n  }\n\n  const register = await importJson('../../../../fixtures/register.json', import.meta.url);\n  const manufacturer = {\n    ...manufacturers[manufacturerKey],\n    key: manufacturerKey,\n    color: register.colors[manufacturerKey],\n    fixtures: (register.manufacturers[manufacturerKey] || []).map(\n      (fixtureKey) => ({\n        key: fixtureKey,\n        name: register.filesystem[`${manufacturerKey}/${fixtureKey}`].name,\n        categories: Object.keys(register.categories).filter(\n          (category) => register.categories[category].includes(`${manufacturerKey}/${fixtureKey}`),\n        ),\n      }),\n    ),\n  };\n\n  return {\n    body: manufacturer,\n  };\n}\n"
  },
  {
    "path": "ui/api/routes/manufacturers/_manufacturerKey.json",
    "content": "{\n  \"parameters\": [\n    {\n      \"name\": \"manufacturerKey\",\n      \"in\": \"path\",\n      \"required\": true,\n      \"schema\": {\n        \"type\": \"string\",\n        \"pattern\": \"^[a-z0-9\\\\-]+$\"\n      }\n    }\n  ],\n  \"get\": {\n    \"operationId\": \"getManufacturerByKey\",\n    \"description\": \"Returns information about a specific manufacturer.\",\n    \"tags\": [\"manufacturers\"],\n    \"responses\": {\n      \"200\": {\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"key\": {\n                  \"type\": \"string\"\n                },\n                \"name\": {\n                  \"type\": \"string\"\n                },\n                \"comment\": {\n                  \"type\": \"string\"\n                },\n                \"website\": {\n                  \"type\": \"string\"\n                },\n                \"rdmId\": {\n                  \"type\": \"integer\"\n                },\n                \"color\": {\n                  \"type\": \"string\"\n                },\n                \"fixtures\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                      \"key\": {\n                        \"type\": \"string\"\n                      },\n                      \"name\": {\n                        \"type\": \"string\"\n                      },\n                      \"categories\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                          \"type\": \"string\"\n                        }\n                      }\n                    },\n                    \"required\": [\n                      \"key\",\n                      \"name\"\n                    ],\n                    \"additionalProperties\": false\n                  }\n                }\n              },\n              \"required\": [\n                \"key\",\n                \"name\",\n                \"color\",\n                \"fixtures\"\n              ],\n              \"additionalProperties\": false\n            }\n          }\n        }\n      },\n      \"404\": {\n        \"$ref\": \"../../openapi.json#/components/responses/404-NotFoundError\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/manufacturers/index.js",
    "content": "import importJson from '../../../../lib/import-json.js';\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../../index.js' */\n\n/**\n * Returns general information about all manufacturers.\n * @param {OpenApiBackendContext} context Passed from OpenAPI Backend.\n * @returns {Promise<ApiResponse>} The handled response.\n */\nexport async function getManufacturers(context) {\n  const manufacturers = await importJson('../../../../fixtures/manufacturers.json', import.meta.url);\n  const register = await importJson('../../../../fixtures/register.json', import.meta.url);\n\n  const manufacturerData = {};\n\n  for (const manufacturerKey of Object.keys(manufacturers)) {\n    if (manufacturerKey !== '$schema') {\n      manufacturerData[manufacturerKey] = {\n        name: manufacturers[manufacturerKey].name,\n        fixtureCount: register.manufacturers[manufacturerKey].length,\n        color: register.colors[manufacturerKey],\n      };\n    }\n  }\n\n  return {\n    body: manufacturerData,\n  };\n}\n"
  },
  {
    "path": "ui/api/routes/manufacturers/index.json",
    "content": "{\n  \"get\": {\n    \"operationId\": \"getManufacturers\",\n    \"description\": \"Returns general information about all manufacturers.\",\n    \"tags\": [\"manufacturers\"],\n    \"responses\": {\n      \"200\": {\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"type\": \"object\",\n              \"additionalProperties\": {\n                \"type\": \"object\",\n                \"properties\": {\n                  \"name\": {\n                    \"type\": \"string\"\n                  },\n                  \"fixtureCount\": {\n                    \"type\": \"integer\"\n                  },\n                  \"color\": {\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [\n                  \"name\",\n                  \"fixtureCount\",\n                  \"color\"\n                ],\n                \"additionalProperties\": false\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/plugins/_pluginKey.js",
    "content": "import importJson from '../../../../lib/import-json.js';\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../../index.js' */\n\n/**\n * Returns general information about import and export plugins.\n * @param {OpenApiBackendContext} ctx Passed from OpenAPI Backend.\n * @returns {Promise<ApiResponse>} The handled response.\n */\nexport async function getPluginByKey({ request }) {\n  let { pluginKey } = request.params;\n\n  const plugins = await importJson('../../../../plugins/plugins.json', import.meta.url);\n\n  if (!(pluginKey in plugins.data)) {\n    return {\n      statusCode: 404,\n      body: {\n        error: 'Plugin not found',\n      },\n    };\n  }\n\n  if (plugins.data[pluginKey].outdated) {\n    pluginKey = plugins.data[pluginKey].newPlugin;\n  }\n\n  const pluginData = await importJson(`../../../../plugins/${pluginKey}/plugin.json`, import.meta.url);\n\n  return {\n    body: {\n      key: pluginKey,\n      name: pluginData.name,\n      previousVersions: pluginData.previousVersions || {},\n      description: pluginData.description.join('\\n'),\n      links: pluginData.links,\n      fixtureUsage: pluginData.fixtureUsage && pluginData.fixtureUsage.join('\\n'),\n      fileLocations: pluginData.fileLocations,\n      additionalInfo: pluginData.additionalInfo && pluginData.additionalInfo.join('\\n'),\n      helpWanted: pluginData.helpWanted,\n      exportPluginVersion: plugins.data[pluginKey].exportPluginVersion,\n      importPluginVersion: plugins.data[pluginKey].importPluginVersion,\n    },\n  };\n}\n"
  },
  {
    "path": "ui/api/routes/plugins/_pluginKey.json",
    "content": "{\n  \"parameters\": [\n    {\n      \"name\": \"pluginKey\",\n      \"in\": \"path\",\n      \"required\": true,\n      \"schema\": {\n        \"type\": \"string\",\n        \"pattern\": \"^[a-z0-9_.-]+$\"\n      }\n    }\n  ],\n  \"get\": {\n    \"operationId\": \"getPluginByKey\",\n    \"description\": \"Returns information about a specific import and export plugin. If an outdated plugin is requested, the information for the renamed plugin is returned.\",\n    \"tags\": [\"plugins\"],\n    \"responses\": {\n      \"200\": {\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"key\": {\n                  \"type\": \"string\"\n                },\n                \"name\": {\n                  \"type\": \"string\"\n                },\n                \"previousVersions\": {\n                  \"type\": \"object\",\n                  \"additionalProperties\": {\n                    \"type\": \"string\"\n                  }\n                },\n                \"description\": {\n                  \"type\": \"string\"\n                },\n                \"links\": {\n                  \"type\": \"object\",\n                  \"minProperties\": 1,\n                  \"additionalProperties\": {\n                    \"type\": \"string\"\n                  }\n                },\n                \"fixtureUsage\": {\n                  \"type\": \"string\"\n                },\n                \"fileLocations\": {\n                  \"type\": \"object\",\n                  \"minProperties\": 1,\n                  \"properties\": {\n                    \"subDirectoriesAllowed\": {\n                      \"type\": \"boolean\"\n                    }\n                  },\n                  \"additionalProperties\": {\n                    \"type\": \"object\",\n                    \"minProperties\": 1,\n                    \"properties\": {\n                      \"main\": {\n                        \"type\": \"string\"\n                      },\n                      \"user\": {\n                        \"type\": \"string\"\n                      }\n                    }\n                  }\n                },\n                \"additionalInfo\": {\n                  \"type\": \"string\"\n                },\n                \"helpWanted\": {\n                  \"type\": \"string\"\n                },\n                \"exportPluginVersion\": {\n                  \"type\": \"string\"\n                },\n                \"importPluginVersion\": {\n                  \"type\": \"string\"\n                }\n              },\n              \"required\": [\n                \"key\",\n                \"name\",\n                \"previousVersions\",\n                \"description\",\n                \"links\"\n              ],\n              \"additionalProperties\": false\n            }\n          }\n        }\n      },\n      \"404\": {\n        \"$ref\": \"../../openapi.json#/components/responses/404-NotFoundError\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/plugins/index.js",
    "content": "import importJson from '../../../../lib/import-json.js';\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../../index.js' */\n\n/**\n * Returns general information about import and export plugins.\n * @param {OpenApiBackendContext} context Passed from OpenAPI Backend.\n * @returns {Promise<ApiResponse>} The handled response.\n */\nexport async function getPlugins(context) {\n  const plugins = await importJson('../../../../plugins/plugins.json', import.meta.url);\n\n  return {\n    body: plugins,\n  };\n}\n"
  },
  {
    "path": "ui/api/routes/plugins/index.json",
    "content": "{\n  \"get\": {\n    \"operationId\": \"getPlugins\",\n    \"description\": \"Returns general information about import and export plugins.\",\n    \"tags\": [\"plugins\"],\n    \"responses\": {\n      \"200\": {\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"importPlugins\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"type\": \"string\"\n                  }\n                },\n                \"exportPlugins\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"type\": \"string\"\n                  }\n                },\n                \"data\": {\n                  \"type\": \"object\",\n                  \"additionalProperties\": {\n                    \"type\": \"object\",\n                    \"properties\": {\n                      \"name\": {\n                        \"type\": \"string\"\n                      },\n                      \"outdated\": {\n                        \"constant\": true\n                      },\n                      \"newPlugin\": {\n                        \"type\": \"string\"\n                      },\n                      \"importPluginVersion\": {\n                        \"type\": \"string\"\n                      },\n                      \"exportPluginVersion\": {\n                        \"type\": \"string\"\n                      },\n                      \"exportTests\": {\n                        \"type\": \"array\",\n                        \"items\": {\n                          \"type\": \"string\"\n                        }\n                      }\n                    },\n                    \"required\": [\n                      \"name\"\n                    ],\n                    \"dependencies\": {\n                      \"outdated\": [\"newPlugin\"],\n                      \"newPlugin\": [\"outdated\"],\n                      \"exportPluginVersion\": [\"exportTests\"],\n                      \"exportTests\": [\"exportPluginVersion\"]\n                    },\n                    \"additionalProperties\": false\n                  }\n                }\n              },\n              \"required\": [\n                \"importPlugins\",\n                \"exportPlugins\",\n                \"data\"\n              ],\n              \"additionalProperties\": false\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes/submit-feedback.js",
    "content": "import createIssue from '../../../lib/create-github-issue.js';\nimport { fixtureFromRepository } from '../../../lib/model.js';\n/** @import { Context as OpenApiBackendContext } from 'openapi-backend' */\n/** @import { ApiResponse } from '../index.js' */\n\n/**\n * Takes the input from the client side script and creates an issue with the given feedback.\n * @param {OpenApiBackendContext} ctx Passed from OpenAPI Backend.\n * @returns {ApiResponse} The handled response.\n */\nexport async function createFeedbackIssue({ request }) {\n  const {\n    type,\n    context,\n    location,\n    helpWanted,\n    message,\n    githubUsername,\n  } = request.requestBody;\n\n  let title;\n  const issueContentData = {};\n  const labels = ['via-editor'];\n\n  if (type === 'plugin') {\n    title = `Feedback for plugin \\`${context}\\``;\n    labels.push('component-plugin');\n  }\n  else {\n    title = `Feedback for fixture \\`${context}\\``;\n    labels.push('component-fixture');\n\n    const [manufacturerKey, fixtureKey] = context.split('/');\n    const fixture = await fixtureFromRepository(manufacturerKey, fixtureKey);\n\n    issueContentData.Manufacturer = fixture.manufacturer.name;\n    issueContentData.Fixture = `[${fixture.name}](${fixture.url})`;\n  }\n\n  issueContentData['Problem location'] = location;\n  issueContentData['Problem description'] = helpWanted;\n  issueContentData.Message = message;\n\n  const lines = Object.entries(issueContentData).filter(\n    ([key, value]) => value !== null,\n  ).map(([key, value]) => {\n    const separator = value.includes('\\n') ? '\\n' : ' ';\n    return `**${key}**:${separator}${value}`;\n  });\n\n  if (githubUsername) {\n    const isValidUsername = /^[\\dA-Za-z]+$/.test(githubUsername);\n    const githubUsernameMarkdown = isValidUsername ? `@${githubUsername}` : `**${githubUsername}**`;\n    lines.push(`\\nThank you ${githubUsernameMarkdown}!`);\n  }\n\n  let issueUrl;\n  let error;\n  try {\n    issueUrl = await createIssue(title, lines.join('\\n'), labels);\n    console.log(`Created issue at ${issueUrl}`);\n  }\n  catch (createIssueError) {\n    error = createIssueError.message;\n  }\n\n  return {\n    statusCode: 201,\n    body: {\n      issueUrl,\n      error,\n    },\n  };\n}\n"
  },
  {
    "path": "ui/api/routes/submit-feedback.json",
    "content": "{\n  \"post\": {\n    \"operationId\": \"createFeedbackIssue\",\n    \"description\": \"Takes the input from the client side script and creates a GitHub issue with the given feedback.\",\n    \"tags\": [\"root\"],\n    \"requestBody\": {\n      \"required\": true,\n      \"content\": {\n        \"application/json\": {\n          \"schema\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"type\": {\n                \"type\": \"string\",\n                \"enum\": [\"fixture\", \"capability\", \"plugin\"]\n              },\n              \"context\": {\n                \"type\": \"string\",\n                \"description\": \"The fixture key or plugin key.\"\n              },\n              \"location\": {\n                \"type\": \"string\",\n                \"nullable\": true\n              },\n              \"helpWanted\": {\n                \"type\": \"string\",\n                \"nullable\": true\n              },\n              \"message\": {\n                \"type\": \"string\"\n              },\n              \"githubUsername\": {\n                \"type\": \"string\"\n              }\n            },\n            \"required\": [\n              \"type\",\n              \"context\",\n              \"location\",\n              \"helpWanted\",\n              \"message\",\n              \"githubUsername\"\n            ],\n            \"additionalProperties\": false\n          }\n        }\n      }\n    },\n    \"responses\": {\n      \"201\": {\n        \"description\": \"Issue created or error occured.\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"issueUrl\": {\n                  \"type\": \"string\",\n                  \"nullable\": true\n                },\n                \"error\": {\n                  \"type\": \"string\",\n                  \"nullable\": true\n                }\n              },\n              \"required\": [\n                \"issueUrl\",\n                \"error\"\n              ],\n              \"additionalProperties\": false\n            },\n            \"example\": {\n              \"issueUrl\": \"https://github.com/OpenLightingProject/open-fixture-library/issues/1154\"\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/api/routes.js",
    "content": "export { getSearchResults } from './routes/get-search-results.js';\nexport { createFeedbackIssue } from './routes/submit-feedback.js';\nexport { createFixtureFromEditor } from './routes/fixtures/from-editor.js';\nexport { importFixtureFile } from './routes/fixtures/import.js';\nexport { submitFixtures } from './routes/fixtures/submit.js';\nexport { getManufacturers } from './routes/manufacturers/index.js';\nexport { getManufacturerByKey } from './routes/manufacturers/_manufacturerKey.js';\nexport { getPlugins } from './routes/plugins/index.js';\nexport { getPluginByKey } from './routes/plugins/_pluginKey.js';\n"
  },
  {
    "path": "ui/assets/icons/icons.js",
    "content": "// read all SVG files in this directory (and subdirectories) into icons object\n// see https://webpack.js.org/guides/dependency-management/#requirecontext\n// eslint-disable-next-line unicorn/prefer-module\nconst resolve = require.context('.', true, /\\.svg$/);\n\nconst getIconPath = (key) => key.match(/^\\.\\/(.+)\\.svg$/)[1];\n\nexport default Object.fromEntries(resolve.keys().map(\n  (key) => [getIconPath(key), resolve(key)],\n));\n"
  },
  {
    "path": "ui/assets/scripts/editor-utilities.js",
    "content": "import { v4 as uuidv4 } from 'uuid';\n\nexport const constants = {\n  RESOLUTION_8BIT: 1,\n  RESOLUTION_16BIT: 2,\n  RESOLUTION_24BIT: 3,\n  RESOLUTION_32BIT: 4,\n};\n\n/**\n * @returns {object} An empty object to be used as a form state for `vue-form`.\n */\nexport function getEmptyFormState() {\n  return {};\n}\n\n/**\n * @returns {object} An empty fixture object.\n */\nexport function getEmptyFixture() {\n  return {\n    key: '[new]',\n    useExistingManufacturer: true,\n    manufacturerKey: '',\n    newManufacturerName: '',\n    newManufacturerWebsite: '',\n    newManufacturerComment: '',\n    newManufacturerRdmId: null,\n    name: '',\n    shortName: '',\n    categories: [],\n    comment: '',\n    links: [\n      getEmptyLink('manual'),\n      getEmptyLink('productPage'),\n      getEmptyLink('video'),\n    ],\n    rdmModelId: null,\n    rdmSoftwareVersion: '',\n    physical: getEmptyPhysical(),\n    modes: [getEmptyMode()],\n    metaAuthor: '',\n    availableChannels: {},\n  };\n}\n\n/**\n * @param {string} linkType The type of the new link.\n * @returns {object} An empty fixture link object.\n */\nexport function getEmptyLink(linkType = 'manual') {\n  return {\n    uuid: uuidv4(),\n    type: linkType,\n    url: '',\n  };\n}\n\n/**\n * @returns {object} An empty fixture's or mode's physical object.\n */\nexport function getEmptyPhysical() {\n  return {\n    dimensions: null,\n    weight: null,\n    power: null,\n    DMXconnector: '',\n    DMXconnectorNew: '',\n    bulb: {\n      type: '',\n      colorTemperature: null,\n      lumens: null,\n    },\n    lens: {\n      name: '',\n      degreesMinMax: null,\n    },\n  };\n}\n\n/**\n * @returns {object} An empty mode object.\n */\nexport function getEmptyMode() {\n  return {\n    uuid: uuidv4(),\n    name: '',\n    shortName: '',\n    rdmPersonalityIndex: null,\n    enablePhysicalOverride: false,\n    physical: getEmptyPhysical(),\n    channels: [],\n  };\n}\n\n/**\n * @returns {object} An empty channel object.\n */\nexport function getEmptyChannel() {\n  return {\n    uuid: uuidv4(),\n    editMode: '',\n    modeId: '',\n    name: '',\n    resolution: constants.RESOLUTION_8BIT,\n    dmxValueResolution: constants.RESOLUTION_8BIT,\n    defaultValue: '',\n    highlightValue: '',\n    constant: null,\n    precedence: '',\n    wheel: {\n      direction: '',\n      slots: [],\n    },\n    wizard: {\n      show: false,\n      start: 0,\n      width: 10,\n      count: 3,\n      templateCapability: getEmptyCapability(),\n    },\n    capabilities: [getEmptyCapability()],\n  };\n}\n\n/**\n * @param {string} coarseChannelId The UUID of the coarse channel.\n * @param {number} resolution The resolution of the newly created fine channel.\n * @returns {object} An empty fine channel object for the given coarse channel.\n */\nexport function getEmptyFineChannel(coarseChannelId, resolution) {\n  return {\n    uuid: uuidv4(),\n    coarseChannelId,\n    resolution,\n  };\n}\n\n/**\n * @returns {object} An empty capability object.\n */\nexport function getEmptyCapability() {\n  return {\n    uuid: uuidv4(),\n    open: true,\n    dmxRange: null,\n    type: '',\n    typeData: {},\n  };\n}\n\n/**\n * @returns {object} An empty wheel slot object.\n */\nexport function getEmptyWheelSlot() {\n  return {\n    uuid: uuidv4(),\n    type: '',\n    typeData: {},\n  };\n}\n\n/**\n * @param {object} channel The channel object.\n * @returns {boolean} False if the channel object is still empty / unchanged, true otherwise.\n */\nexport function isChannelChanged(channel) {\n  return Object.keys(channel).some((property) => {\n    if (['uuid', 'editMode', 'modeId', 'wizard'].includes(property)) {\n      return false;\n    }\n\n    if (['defaultValue', 'highlightValue', 'invert', 'constant', 'crossfade'].includes(property)) {\n      return channel[property] !== null;\n    }\n\n    if (property === 'resolution' || property === 'dmxValueResolution') {\n      return channel[property] !== constants.RESOLUTION_8BIT;\n    }\n\n    if (property === 'capabilities') {\n      return channel.capabilities.some(\n        (capability) => isCapabilityChanged(capability),\n      );\n    }\n\n    return channel[property] !== '';\n  });\n}\n\n/**\n * @param {object} capability The capability object.\n * @returns {boolean} False if the capability object is still empty / unchanged, true otherwise.\n */\nexport function isCapabilityChanged(capability) {\n  if (capability.dmxRange !== null) {\n    return true;\n  }\n\n  if (capability.type !== '') {\n    return true;\n  }\n\n  return Object.values(capability.typeData).some((value) => value !== '' && value !== null);\n}\n\n/**\n * @param {string | null} hexString A string of comma-separated hex values, or null.\n * @returns {string[] | null} The hex codes as array of strings.\n */\nexport function colorsHexStringToArray(hexString) {\n  if (typeof hexString !== 'string') {\n    return null;\n  }\n\n  const hexArray = hexString.split(/\\s*,\\s*/).map((hex) => hex.trim().toLowerCase()).filter(\n    (hex) => hex.match(/^#[\\da-f]{6}$/),\n  );\n\n  if (hexArray.length === 0) {\n    return null;\n  }\n\n  return hexArray;\n}\n\n/**\n * @param {object} channel The channel object that shall be sanitized.\n * @returns {object} A clone of the channel object without properties that are just relevant for displaying it in the channel dialog.\n */\nexport function getSanitizedChannel(channel) {\n  const sanitizedChannel = structuredClone(channel);\n  delete sanitizedChannel.editMode;\n  delete sanitizedChannel.modeId;\n  delete sanitizedChannel.wizard;\n\n  return sanitizedChannel;\n}\n"
  },
  {
    "path": "ui/assets/scripts/fixture-link-types.js",
    "content": "export default {\n  linkTypeIconNames: {\n    manual: 'file-pdf',\n    productPage: 'web',\n    video: 'youtube',\n    other: 'link-variant',\n  },\n  linkTypeNames: {\n    manual: 'Manual',\n    productPage: 'Product page',\n    video: 'Video',\n    other: 'Other',\n  },\n};\n"
  },
  {
    "path": "ui/assets/styles/fonts.scss",
    "content": "// commented flavors are not included in the repository\n$lato-flavor-list: (\n  // \"Hairline\": 100,\n  // \"Thin\": 200,\n  \"Light\": 300,\n  \"Regular\": 400,\n  // \"Medium\": 500,\n  // \"Semibold\": 600,\n  \"Bold\": 700,\n  // \"Heavy\": 800,\n  // \"Black\": 900\n);\n\n// v2.015 from https://www.latofonts.com/lato-free-fonts/\n@each $flavor, $weight in $lato-flavor-list {\n  $url: \"/fonts/LatoLatin/LatoLatin-#{$flavor}\";\n\n  @font-face {\n    font-family: LatoLatin;\n    font-style: normal;\n    font-weight: $weight;\n    src:\n      local(\"Lato #{$flavor}\"),\n      local(\"Lato-#{$flavor}\"),\n      url(\"#{$url}.woff2\") format(\"woff2\");\n    font-display: fallback;\n  }\n\n  @font-face {\n    font-family: LatoLatin;\n    font-style: italic;\n    font-weight: $weight;\n    src:\n      local(\"Lato #{$flavor} Italic\"),\n      local(\"Lato-#{$flavor}Italic\"),\n      url(\"#{$url}Italic.woff2\") format(\"woff2\");\n    font-display: fallback;\n  }\n}\n\n// v21 from https://google-webfonts-helper.herokuapp.com/fonts/inconsolata\n@font-face {\n  font-family: Inconsolata;\n  font-weight: 400;\n  src:\n    local(\"Inconsolata Regular\"),\n    local(\"Inconsolata-Regular\"),\n    url(\"/fonts/Inconsolata/Inconsolata-Regular.woff2\") format(\"woff2\");\n  font-display: fallback;\n}\n"
  },
  {
    "path": "ui/assets/styles/global.scss",
    "content": "// Automatically loaded in SCSS files in global namespace\n\n@forward \"./mixins.scss\";\n@forward \"./theming.scss\";\n@forward \"./vars.scss\";\n"
  },
  {
    "path": "ui/assets/styles/mixins.scss",
    "content": "@use \"sass:string\";\n@use \"./theming.scss\";\n\n$animation-number: 0 !default;\n\n@mixin animation-keyframes {\n  $animation-number: $animation-number + 1 !global;\n  $name: string.unquote(\"ofl-animation-#{$animation-number}\");\n\n  animation-name: $name;\n\n  @at-root {\n    @keyframes #{$name} {\n      @content;\n    }\n  }\n}\n\n/// Usage:\n///   @include mobile-hover-emulation((\n///     background-color: <hover theme color name>,\n///     // ...\n///   ), 0.1s, 0.3s);\n///\n/// Result:\n///   & {\n///     transition-duration: 0.1s;\n///   }\n///\n///   #ofl-root.no-touch &:hover {\n///     background-color: <themed hover color>;\n///   }\n///   #ofl-root.touch &:hover {\n///     animation-delay: 0.3s;\n///     animation-duration: 0.1s;\n///     animation-fill-mode: both;\n///     animation-name: ofl-animation-1;\n///   }\n///\n///   @keyframes ofl-animation-1 {\n///     from {\n///       background-color: <themed hover color>;\n///     }\n///     to {\n///       background-color: unset;\n///     }\n///   }\n@mixin mobile-hover-emulation($transition-map, $transition-duration: 0.2s, $mobile-hover-delay: 0.2s) {\n  transition-duration: $transition-duration;\n\n  #ofl-root.no-touch &:hover {\n    @each $property, $color-name in $transition-map {\n      #{$property}: theming.theme-color($color-name);\n    }\n  }\n\n  #ofl-root.touch &:hover {\n    animation-duration: $transition-duration;\n    animation-delay: $mobile-hover-delay;\n    animation-fill-mode: both;\n\n    @include animation-keyframes {\n      from {\n        @each $property, $color-name in $transition-map {\n          #{$property}: theming.theme-color($color-name);\n        }\n      }\n\n      to {\n        @each $property, $color-name in $transition-map {\n          #{$property}: unset;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ui/assets/styles/style.scss",
    "content": "@use \"./fonts.scss\";\n\n@each $theme-name, $theme in $themes {\n  [data-theme=\"#{$theme-name}\"] {\n    @each $color-name, $color in $theme {\n      --theme-#{$color-name}: #{ color-to-rgb-string($color) };\n    }\n  }\n}\n\nhtml,\nbody {\n  padding: 0;\n  margin: 0;\n  font: 12pt/2 $font-stack-text;\n  color: theme-color(text-primary);\n  overflow-wrap: break-word;\n  background-color: theme-color(page-background);\n  text-rendering: optimizelegibility;\n  transition: background-color 0.3s, color 0.3s;\n}\n\nhtml {\n  overflow-y: scroll;\n}\n\n// IE9 / IE10 does not do this automatically\n[hidden] {\n  display: none;\n}\n\nh1 {\n  margin: 1.5rem 0;\n  font-size: 2rem;\n  font-weight: 300;\n  line-height: 2.5rem;\n}\n\nh2 {\n  margin: 0;\n  font-size: 1.5rem;\n  font-weight: 400;\n}\n\nh3 {\n  margin: 1rem 0 0;\n  font-size: 1.2rem;\n  font-weight: 700;\n}\n\nh4 {\n  margin: 0.8rem 0 0;\n  font-size: 1rem;\n  font-weight: 700;\n}\n\np {\n  margin: 1rem 0;\n}\n\nsection {\n  padding-top: 1.2ex;\n}\n\n.centered {\n  text-align: center;\n}\n\n.clearfix {\n  clear: both;\n}\n\nlabel {\n  max-width: 100%;\n}\n\n.hint {\n  display: block;\n  font-size: 0.8rem;\n  line-height: 1.5;\n  color: theme-color(text-secondary);\n}\n\ntemplate {\n  display: none !important;\n}\n\n#ofl-root.js .no-js {\n  display: none;\n}\n\n#ofl-root.no-js .only-js {\n  display: none;\n}\n\ncode {\n  font-family: $font-stack-code;\n  font-weight: 400;\n  color: theme-color(text-secondary);\n}\n\nh1 code,\nh2 code,\nh3 code,\ncode.channel-key {\n  margin: 0 1ex;\n}\n\na {\n  color: theme-color(link);\n  text-decoration: none;\n  fill: theme-color(icon);\n  transition: color 0.1s, fill 0.1s, background-color 0.1s;\n\n  &:hover,\n  &:focus {\n    color: theme-color(link-hover);\n    fill: theme-color(icon-hover);\n  }\n}\n\ntextarea {\n  min-height: 4em;\n  resize: vertical;\n}\n\nselect {\n  width: 30ex;\n}\n\ninput[type=\"number\"] {\n  width: 10ex;\n}\n\ntextarea,\ninput[type=\"text\"],\ninput[type=\"email\"],\ninput[type=\"search\"],\ninput[type=\"url\"] {\n  width: 40ex;\n}\n\nselect,\ntextarea,\ninput[type=\"text\"],\ninput[type=\"email\"],\ninput[type=\"search\"],\ninput[type=\"url\"],\ninput[type=\"number\"] {\n  box-sizing: border-box;\n  max-width: 100%;\n  padding: 0.4em;\n  font-family: $font-stack-text;\n  font-size: 0.95em;\n  color: theme-color(text-primary);\n  background: theme-color(form-field-background);\n  border: 1px solid theme-color(form-field-border);\n  border-radius: 3px;\n  transition: background-color 0.2s, border-color 0.2s;\n\n  &:focus {\n    border-color: $blue-300;\n  }\n\n  &:disabled {\n    background: $grey-100;\n    opacity: 0.9;\n  }\n\n  &.vf-touched.vf-invalid,\n  &.vf-submitted.vf-invalid,\n  &.vf-touched[class^=\"vf-invalid-\"],\n  .vf-touched.vf-invalid &,\n  .vf-submitted.vf-invalid &,\n  .vf-touched[class^=\"vf-invalid-\"] & {\n    border-color: red;\n    box-shadow: 0 0 4px rgba(255, 0, 0, 40%);\n  }\n}\n\ntextarea[readonly] {\n  width: 100%;\n  height: 15em;\n  padding: 1em;\n  overflow: auto;\n  font-family: $font-stack-code;\n  font-size: 0.9em;\n  font-weight: 400;\n  line-height: 1.3;\n  color: theme-color(text-primary);\n  white-space: pre-wrap;\n  resize: none;\n  background: theme-color(header-background);\n  border: none;\n}\n\n.error-message {\n  display: block;\n  color: red;\n\n  & div::before {\n    display: inline-block;\n    width: 1em;\n    height: 1em;\n    margin: -2px 1ex 0 0;\n    font-weight: 700;\n    line-height: 1em;\n    vertical-align: middle;\n    color: white;\n    text-align: center;\n    content: \"!\";\n    background: red;\n    border-radius: 9999px;\n  }\n}\n\ninput.addition {\n  margin-left: 1ex;\n}\n\nselect.empty {\n  font-style: italic;\n  color: theme-color(text-secondary);\n\n  & > option {\n    font-style: normal;\n    color: theme-color(text-primary);\n  }\n}\n\ninput::placeholder {\n  font-style: italic;\n  color: theme-color(text-secondary);\n  opacity: 1; // Firefox sets a default opacity\n}\n\nbutton,\na.button {\n  &.primary,\n  &.secondary {\n    display: inline-block;\n    padding: 0.5em 3ex;\n    font-size: 0.9em;\n    font-weight: 700;\n    line-height: 1.4;\n    cursor: pointer;\n    border: 1px solid;\n    border-radius: 2px;\n    transition: 0.2s background-color;\n\n    &.inline {\n      padding: 4px 6px;\n      font-size: 0.85em;\n    }\n\n    &:disabled {\n      cursor: default;\n      opacity: 0.5;\n    }\n\n    &:not(:disabled):active {\n      position: relative;\n      top: 1px;\n    }\n  }\n\n  &.primary {\n    color: theme-color(button-primary-text);\n    background-color: theme-color(button-primary-background);\n    border-color: theme-color(button-primary-border);\n\n    &:not(:disabled):hover,\n    &:not(:disabled):focus {\n      outline: 0;\n      background-color: theme-color(button-primary-background-hover);\n    }\n  }\n\n  &.secondary {\n    color: theme-color(button-secondary-text);\n    background-color: theme-color(button-secondary-background);\n    border-color: theme-color(button-secondary-border);\n\n    &:not(:disabled):hover,\n    &:not(:disabled):focus {\n      outline: 0;\n      background-color: theme-color(button-secondary-background-hover);\n    }\n  }\n}\n\n.button-bar {\n  margin: 2ex 0 0;\n\n  & button,\n  & .button {\n    margin-top: 1ex;\n    margin-right: 1ex;\n  }\n\n  &.right {\n    text-align: right;\n\n    & button,\n    & .button {\n      margin-right: 0;\n      margin-left: 1ex;\n    }\n  }\n}\n\n@media (max-width: $tablet) {\n  html,\n  body {\n    font-size: 14px;\n  }\n}\n\n.icon-button {\n  $icon-size: 1.4em;\n  $padding: 0.3em;\n\n  position: relative;\n  display: inline-block;\n  width: 0;\n  height: #{$icon-size + 2 * $padding};\n  padding: 0 0 0 #{$icon-size + 2 * $padding};\n  overflow: hidden;\n  font-size: 1em;\n  vertical-align: middle;\n  color: theme-color(icon);\n  cursor: pointer;\n  border: 1px solid;\n  border-radius: 3px;\n\n  &::-moz-focus-inner {\n    border: 0;\n  }\n\n  & > .icon {\n    position: absolute;\n    top: $padding;\n    left: $padding;\n    display: block;\n    width: $icon-size;\n    height: $icon-size;\n    fill: currentcolor;\n  }\n\n  &:not(.close) {\n    background-color: theme-color(button-primary-background, 0%);\n    border-color: theme-color(button-primary-background, 0%);\n\n    @include mobile-hover-emulation((\n      background-color: button-primary-background-hover,\n      color: button-primary-text\n    ));\n\n    &:focus {\n      outline: none;\n      border-color: $blue-300;\n    }\n\n    &:active {\n      color: $primary-text-light;\n      background-color: theme-color(blue-background-active);\n      border-color: rgba($blue-300, 0%);\n    }\n  }\n\n  &.close {\n    background-color: rgba($red-700, 0%);\n    border-color: rgba($red-700, 0%);\n\n    &:focus {\n      color: theme-color(icon);\n      outline: none;\n      border-color: $red-700;\n    }\n\n    &:hover {\n      color: $primary-text-light;\n      background-color: $red-700;\n    }\n\n    &:active {\n      color: $primary-text-light;\n      background-color: $red-300;\n      border-color: rgba($red-700, 0%);\n    }\n  }\n}\n\n.card {\n  $card-spacing: 1rem;\n\n  position: relative;\n  box-sizing: border-box;\n  padding: 1rem;\n  margin-bottom: $card-spacing;\n  text-align: left;\n  background-color: theme-color(card-background);\n  border-radius: 3px;\n  box-shadow: 0 2px 4px theme-color(divider);\n  fill: theme-color(icon);\n  transition: background-color 0.3s;\n\n  & .icon-button.close {\n    float: right;\n  }\n\n  & a.big-button {\n    margin: 1rem -1rem -1rem;\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n  }\n\n  &.dark {\n    color: $primary-text-light;\n    fill: $icon-light;\n  }\n\n  &.light-green {\n    background: theme-color(light-green-background);\n  }\n\n  &.blue {\n    background: theme-color(blue-background);\n  }\n\n  &.yellow {\n    background-color: theme-color(yellow-background);\n  }\n\n  &.red {\n    background-color: theme-color(red-background);\n  }\n\n  &.orange {\n    background: theme-color(orange-background);\n  }\n\n  &:target {\n    animation-duration: 1.2s;\n    animation-timing-function: ease;\n    animation-delay: 0.5s;\n    animation-fill-mode: backwards;\n\n    @include animation-keyframes {\n      from {\n        background-color: theme-color(blue-highlight);\n      }\n    }\n  }\n\n  .grid-3 > & {\n    @media (min-width: $phone-landscape) {\n      display: inline-block;\n      width: calc((100% - #{$card-spacing}) / 2);\n      vertical-align: top;\n\n      & > h2,\n      & > .name {\n        overflow: hidden;\n        text-overflow: ellipsis;\n        white-space: nowrap;\n      }\n\n      &:nth-child(2n) {\n        margin-left: $card-spacing;\n      }\n    }\n\n    @media (min-width: $tablet) {\n      width: calc((100% - 2 * #{$card-spacing}) / 3);\n\n      &:nth-child(3n+1) {\n        margin-left: 0;\n      }\n\n      &:nth-child(3n+2),\n      &:nth-child(3n) {\n        margin-left: $card-spacing;\n      }\n    }\n  }\n\n  .grid-4 > & {\n    @media (width >= 440px) {\n      display: inline-block;\n      width: calc((100% - #{$card-spacing}) / 2);\n      vertical-align: top;\n\n      & > h2,\n      & > .name {\n        overflow: hidden;\n        text-overflow: ellipsis;\n        white-space: nowrap;\n      }\n\n      &:nth-child(2n) {\n        margin-left: $card-spacing;\n      }\n    }\n\n    @media (width >= 650px) {\n      width: calc((100% - 2 * #{$card-spacing}) / 3);\n\n      &:nth-child(3n+1) {\n        margin-left: 0;\n      }\n\n      &:nth-child(3n+2),\n      &:nth-child(3n) {\n        margin-left: $card-spacing;\n      }\n    }\n\n    @media (width >= 920px) {\n      width: calc((100% - 3 * #{$card-spacing}) / 4);\n\n      &:nth-child(4n+1) {\n        margin-left: 0;\n      }\n\n      &:nth-child(4n+2),\n      &:nth-child(4n+3),\n      &:nth-child(4n) {\n        margin-left: $card-spacing;\n      }\n    }\n  }\n}\n\n.manufacturer-color {\n  border-left: 0.6rem solid transparent;\n}\n\n.list {\n  padding: 0;\n  margin: 0 -1rem;\n\n  &:only-child {\n    margin: -1rem;\n\n    & li:first-child a {\n      margin-top: 0;\n      border-top-left-radius: 3px;\n      border-top-right-radius: 3px;\n    }\n\n    & li:last-child a {\n      border-bottom-right-radius: 3px;\n      border-bottom-left-radius: 3px;\n    }\n  }\n\n  & > li {\n    list-style: none;\n  }\n\n  & > h2 {\n    padding: 1rem 1rem 0;\n  }\n\n  .name {\n    margin-right: auto;\n  }\n}\n\n.list a,\na.card.slim {\n  padding: 0.5rem 1rem;\n  margin-top: 1px;\n}\n\n.list,\n.card.slim {\n  a,\n  a .hint {\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n\n  .icon {\n    width: 32px;\n    height: 32px;\n\n    &.left {\n      margin-right: 1em;\n    }\n\n    &.right {\n      margin-left: 1em;\n    }\n  }\n}\n\na.card,\n.link,\n.list a {\n  display: block;\n  color: theme-color(text-primary);\n  text-decoration: none;\n  cursor: pointer;\n  transition: background-color 0.2s, fill 0.2s;\n\n  &:hover,\n  &:focus {\n    outline: none;\n    background-color: theme-color(hover-background);\n    fill: theme-color(text-primary);\n\n    &.dark {\n      fill: $primary-text-light;\n    }\n\n    &.light-green {\n      background-color: theme-color(light-green-background-hover);\n    }\n\n    &.blue {\n      background-color: theme-color(blue-background-hover);\n    }\n  }\n\n  &:active {\n    background-color: theme-color(active-background);\n\n    &.light-green {\n      background-color: theme-color(light-green-background-active);\n    }\n\n    &.blue {\n      background-color: theme-color(blue-background-active);\n    }\n  }\n}\n\n.card-category,\n.big-button {\n  min-height: 5rem;\n  padding-left: 5rem;\n\n  & > .icon {\n    position: absolute;\n    top: 1rem;\n    left: 1rem;\n    width: 3rem;\n    height: 3rem;\n  }\n\n  & > h2 {\n    line-height: 3rem;\n  }\n}\n\n.big-button > h2 {\n  font-size: 1.2rem;\n}\n\n// display mode cards in a 2-col layout\n@media (min-width: $tablet) {\n  .fixture-mode {\n    width: calc(50% - 0.5rem);\n\n    &:nth-child(odd) {\n      float: left;\n      clear: left;\n      margin-right: 0.5rem;\n    }\n\n    &:nth-child(even) {\n      float: right;\n      clear: right;\n      margin-left: 0.5rem;\n    }\n  }\n}\n\n@media (max-width: $phone) {\n  .list > li > a > .icon {\n    width: 24px;\n    height: 24px;\n\n    &.left {\n      margin-right: 0.6em;\n    }\n\n    &.right {\n      margin-left: 0.6em;\n    }\n  }\n}\n"
  },
  {
    "path": "ui/assets/styles/theming.scss",
    "content": "@use \"sass:color\";\n@use \"sass:map\";\n@use \"sass:math\";\n@use \"./vars.scss\";\n\n/// Function to get a theme color CSS variable (with fallback to light themed color).\n///\n/// Usage:\n///     background: linear-gradient(to top, red, theme-color(primary));\n///\n/// Output:\n///     background: linear-gradient(to top, red, rgba(255, 127, 0, 1));\n///     background: linear-gradient(to top, red, rgba(var(--theme-primary, 255, 127, 0), 1));\n@function theme-color($color-name, $opacity: 100%) {\n  $default-theme: map.get(vars.$themes, light);\n\n  @if map.has-key($default-theme, $color-name) == false {\n    @error \"Theme color #{$color-name} doesn't exist in light theme.\";\n  }\n\n  @if math.unit($opacity) != \"%\" {\n    @error \"Second parameter of theme-color needs to be a percentage value, like 50%.\";\n  }\n\n  $themed-color: map.get($default-theme, $color-name);\n  $alpha: math.div($opacity, 100%) * color.channel($themed-color, \"alpha\");\n\n  @return #{\"rgba(var(--theme-#{$color-name}, #{color-to-rgb-string($themed-color)}), #{$alpha})\"};\n}\n\n@function color-to-rgb-string($hexColor) {\n  $red: color.channel($hexColor, \"red\");\n  $green: color.channel($hexColor, \"green\");\n  $blue: color.channel($hexColor, \"blue\");\n\n  @return \"#{$red}, #{$green}, #{$blue}\";\n}\n"
  },
  {
    "path": "ui/assets/styles/vars.scss",
    "content": "@use \"sass:color\";\n\n$font-stack-text: \"LatoLatin\", \"Source Sans Pro\", \"Helvetica\", \"Arial\", sans-serif;\n$font-stack-code: \"Inconsolata\", \"Roboto Mono\", \"Source Code Pro\", monospace;\n\n// 2014 Material Design color palettes\n// from https://material.io/design/color/#tools-for-picking-colors\n\n// Material Design Red\n$red-200: #ef9a9a;\n$red-300: #e57373;\n$red-700: #d32f2f;\n\n// Material Design Blue\n$blue-100: #bbdefb;\n$blue-300: #64b5f6;\n$blue-500: #2196f3;\n$blue-600: #1e88e5;\n$blue-700: #1976d2;\n$blue-800: #1565c0;\n\n// Material Design Yellow\n$yellow-300: #fff176;\n$yellow-600: #fdd835;\n$yellow-700: #fbc02d;\n\n// Material Design Orange\n$orange-500: #ff9800;\n$orange-600: #fb8c00;\n$orange-700: #f57c00;\n$orange-800: #ef6c00;\n\n// Material Design Grey\n$grey-50: #fafafa;\n$grey-100: #f5f5f5;\n$grey-200: #eeeeee;\n$grey-300: #e0e0e0;\n\n// Material Design Light Green\n$light-green-500: #8bc34a;\n$light-green-600: #7cb342;\n$light-green-700: #689f38;\n$light-green-800: #558b2f;\n\n// stylelint-disable scss/dollar-variable-colon-space-after -- column alignment is more readable here\n$primary-text-dark:     rgba(0, 0, 0, 87%);\n$secondary-text-dark:   rgba(0, 0, 0, 54%);\n$disabled-text-dark:    rgba(0, 0, 0, 38%);\n$divider-dark:          rgba(0, 0, 0, 12%);\n$icon-dark:             rgba(0, 0, 0, 54%);\n$icon-dark-hover:       rgba(0, 0, 0, 38%);\n$icon-inactive-dark:    rgba(0, 0, 0, 27%);\n$primary-text-light:    rgba(255, 255, 255, 100%);\n$secondary-text-light:  rgba(255, 255, 255, 70%);\n$disabled-text-light:   rgba(255, 255, 255, 50%);\n$divider-light:         rgba(255, 255, 255, 12%);\n$icon-light:            rgba(255, 255, 255, 80%);\n$icon-light-hover:      rgba(255, 255, 255, 65%);\n$icon-inactive-light:   rgba(255, 255, 255, 50%);\n// stylelint-enable scss/dollar-variable-colon-space-after\n\n// from https://material.io/design/color/dark-theme.html#properties\n\n$dark-grey: #121212;\n$dark-grey-elevation-01dp: color.adjust($dark-grey, $lightness: 5%);\n$dark-grey-elevation-02dp: color.adjust($dark-grey, $lightness: 7%);\n$dark-grey-elevation-03dp: color.adjust($dark-grey, $lightness: 8%);\n$dark-grey-elevation-04dp: color.adjust($dark-grey, $lightness: 9%);\n$dark-grey-elevation-06dp: color.adjust($dark-grey, $lightness: 11%);\n$dark-grey-elevation-08dp: color.adjust($dark-grey, $lightness: 12%);\n$dark-grey-elevation-12dp: color.adjust($dark-grey, $lightness: 14%);\n$dark-grey-elevation-16dp: color.adjust($dark-grey, $lightness: 15%);\n$dark-grey-elevation-24dp: color.adjust($dark-grey, $lightness: 16%);\n\n// Width value for media queries\n$tablet: 800px;\n$phone-landscape: 600px;\n$phone: 440px;\n\n// Theme colors\n$themes: (\n  light: (\n    page-background: $grey-200,\n    header-background: $grey-50,\n    hover-background: $grey-300,\n    active-background: $grey-200,\n    card-background: #ffffff,\n    dialog-background: #ffffff,\n\n    text-primary: $primary-text-dark,\n    text-secondary: $secondary-text-dark,\n    text-disabled: $disabled-text-dark,\n\n    divider: $divider-dark,\n    icon: $icon-dark,\n    icon-hover: $icon-dark-hover,\n    icon-inactive: $icon-inactive-dark,\n\n    link: $blue-700,\n    link-hover: $blue-300,\n\n    form-field-background: #ffffff,\n    form-field-border: #cfd6e6,\n\n    button-primary-background: $blue-700,\n    button-primary-background-hover: $blue-300,\n    button-primary-border: $blue-700,\n    button-primary-text: $primary-text-light,\n    button-secondary-background: $grey-50,\n    button-secondary-background-hover: $grey-300,\n    button-secondary-border: $grey-300,\n    button-secondary-text: $secondary-text-dark,\n\n    light-green-background: $light-green-500,\n    light-green-background-hover: $light-green-600,\n    light-green-background-active: $light-green-700,\n\n    blue-highlight: $blue-100,\n    blue-background: $blue-500,\n    blue-background-hover: $blue-600,\n    blue-background-active: $blue-700,\n\n    yellow-background: $yellow-300,\n    yellow-background-hover: $yellow-600,\n\n    red-background: $red-200,\n\n    orange-background: $orange-500,\n    orange-background-hover: $orange-700,\n  ),\n  dark: (\n    page-background: $dark-grey,\n    header-background: $dark-grey-elevation-16dp,\n    active-background: $dark-grey-elevation-12dp,\n    hover-background: #555555,\n    card-background: $dark-grey-elevation-08dp,\n    dialog-background: $dark-grey-elevation-24dp,\n\n    text-primary: $primary-text-light,\n    text-secondary: $secondary-text-light,\n    text-disabled: $disabled-text-light,\n\n    divider: $divider-light,\n    icon: $icon-light,\n    icon-hover: $icon-light-hover,\n    icon-inactive: $icon-inactive-light,\n\n    link: $blue-300,\n    link-hover: $blue-700,\n\n    form-field-background: #000000,\n    form-field-border: #555555,\n\n    button-primary-background: $blue-700,\n    button-primary-background-hover: $blue-300,\n    button-primary-border: $blue-700,\n    button-primary-text: $primary-text-light,\n    button-secondary-background: $dark-grey-elevation-08dp,\n    button-secondary-background-hover: $dark-grey-elevation-02dp,\n    button-secondary-border: $dark-grey-elevation-02dp,\n    button-secondary-text: $secondary-text-light,\n\n    light-green-background: $light-green-700,\n    light-green-background-hover: $light-green-500,\n    light-green-background-active: $light-green-800,\n\n    blue-highlight: $blue-800,\n    blue-background: $blue-700,\n    blue-background-hover: $blue-500,\n    blue-background-active: $blue-800,\n\n    yellow-background: #aa8e00,\n    yellow-background-hover: #dbbb2a,\n\n    red-background: #990000,\n\n    orange-background: $orange-800,\n    orange-background-hover: $orange-500,\n  ),\n);\n"
  },
  {
    "path": "ui/components/A11yDialog.vue",
    "content": "<template>\n  <!-- eslint-disable-next-line vuejs-accessibility/no-aria-hidden-on-focusable -- aria-hidden is dynamically toggled -->\n  <div\n    :id=\"id\"\n    class=\"dialog-container\"\n    :aria-hidden=\"shown ? `false` : `true`\"\n    :aria-labelledby=\"`${id}-dialog-title`\"\n    :role=\"isAlertDialog ? `alertdialog` : undefined\"\n    @click.self=\"overlayClick($event)\">\n\n    <div\n      ref=\"dialog\"\n      role=\"document\"\n      class=\"dialog card\"\n      :class=\"{ wide }\">\n      <div>\n\n        <button\n          v-if=\"!isAlertDialog\"\n          type=\"button\"\n          class=\"icon-button close\"\n          title=\"Close\"\n          @click.prevent=\"hide()\">\n          Close\n          <OflSvg name=\"close\" />\n        </button>\n\n        <h2 :id=\"`${id}-dialog-title`\" tabindex=\"-1\">\n          <slot name=\"title\">{{ title }}</slot>\n        </h2>\n\n        <slot />\n\n      </div>\n    </div>\n\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n@keyframes fade-in {\n  from {\n    opacity: 0;\n  }\n}\n\n@keyframes scale-up {\n  from {\n    transform: scale(0.9);\n  }\n}\n\n$container-fade-duration: 200ms;\n\n.dialog-container {\n  position: fixed;\n  inset: 0;\n  z-index: 1000;\n  display: flex;\n  background-color: rgba(0, 0, 0, 66%);\n  animation: fade-in $container-fade-duration both;\n}\n\n.dialog-container[aria-hidden=\"true\"] {\n  display: none;\n}\n\n.dialog {\n  box-sizing: border-box;\n  min-width: 20rem;\n  max-width: 90%;\n  max-height: 90%;\n  margin: auto;\n  overflow: auto;\n  overscroll-behavior: contain;\n  color: theme-color(text-primary);\n  background-color: theme-color(dialog-background);\n  animation:\n    fade-in 200ms $container-fade-duration both,\n    scale-up 200ms $container-fade-duration both;\n\n  &.wide {\n    width: 1000px;\n  }\n\n  h2:focus {\n    outline: none;\n  }\n\n  // fixes padding not being visible when scrollbar is present\n  &.card {\n    padding: 0;\n\n    & > div {\n      padding: 1rem;\n    }\n  }\n}\n\n@media (max-width: $phone) {\n  // make dialogs cover the whole screen\n  .dialog,\n  .dialog.wide {\n    width: 100%;\n    min-width: none;\n    max-width: none;\n    height: 100%;\n    max-height: none;\n  }\n}\n</style>\n\n<script>\nimport { booleanProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    id: stringProp(\n      (id) => (typeof id === 'string' && id.endsWith('-dialog') ? undefined : 'id should end with \"-dialog\".'),\n    ).required,\n    isAlertDialog: booleanProp().withDefault(false),\n    shown: booleanProp().withDefault(true),\n    title: stringProp().required,\n    wide: booleanProp().withDefault(false),\n  },\n  emits: {\n    show: () => true,\n    hide: () => true,\n  },\n  data() {\n    return {\n      dialog: null,\n    };\n  },\n  watch: {\n    shown: 'update',\n  },\n  async mounted() {\n    const { default: A11yDialog } = await import('a11y-dialog');\n\n    this.dialog = new A11yDialog(this.$el);\n\n    this.dialog.on('show', () => {\n      this.$refs.dialog.scrollTop = 0;\n      this.$emit('show');\n    });\n\n    this.dialog.on('hide', () => this.$emit('hide'));\n\n    this.update();\n  },\n  beforeDestroy() {\n    this.dialog.destroy();\n  },\n  methods: {\n    update() {\n      if (this.shown) {\n        this.show();\n      }\n      else {\n        this.hide();\n      }\n    },\n    show() {\n      this.dialog?.show();\n    },\n    hide() {\n      this.dialog?.hide();\n    },\n    overlayClick() {\n      if (!this.isAlertDialog) {\n        this.hide();\n      }\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/CapabilityTypeIcon.vue",
    "content": "<script>\nimport { instanceOfProp } from 'vue-ts-types';\nimport Capability from '../../lib/model/Capability.js';\n\nexport default {\n  functional: true,\n  props: {\n    capability: instanceOfProp(Capability).required,\n  },\n  render(createElement, context) {\n    const capability = context.props.capability;\n    const wheelSlot = capability.wheelSlot;\n\n    if (capability.type !== 'WheelShake' && wheelSlot !== null && wheelSlot[0] === wheelSlot[1]) {\n      const resource = wheelSlot[0].resource;\n\n      if (resource && resource.hasImage) {\n        const data = {\n          ...context.data,\n          attrs: {\n            ...context.data.attrs,\n            src: resource.imageDataUrl,\n            title: `Capability type: ${capability.type}, slot ${capability.slotNumber[0]} (${wheelSlot[0].name})`,\n          },\n          class: [context.data.class, 'icon', 'gobo-icon'],\n        };\n\n        return createElement('img', data);\n      }\n    }\n\n    return createElement('OflSvg', {\n      ...context.data,\n      props: getIconProperties(capability),\n    });\n  },\n};\n\nconst isAnimationGoboSlot = (slot) => slot.type.startsWith('AnimationGobo');\nconst isAnimationGobo = (capability) => isAnimationGoboSlot(capability.wheelSlot[0]) && isAnimationGoboSlot(capability.wheelSlot[1]);\n\nconst specialIconFunctions = {\n  ShutterStrobe(capability, iconProperties) {\n    if (capability.shutterEffect === 'Closed' || capability.shutterEffect === 'Open') {\n      iconProperties.type = 'color-circle';\n      iconProperties.colors = [capability.shutterEffect === 'Closed' ? '#000000' : '#ffffff'];\n      delete iconProperties.name;\n    }\n    else {\n      iconProperties.name = 'Strobe';\n    }\n  },\n  Intensity(capability, iconProperties) {\n    iconProperties.name = 'dimmer';\n  },\n  ColorIntensity(capability, iconProperties) {\n    iconProperties.name = 'dimmer';\n  },\n  ColorPreset(capability, iconProperties) {\n    iconProperties.name = 'color-changer';\n  },\n  PanContinuous(capability, iconProperties) {\n    if (capability.speed[0].number === 0 && capability.speed[1].number === 0) {\n      iconProperties.name = 'speed-stop';\n    }\n    else if (capability.speed[0].number > 0 || capability.speed[1].number > 0) {\n      iconProperties.name = 'pan-continuous-cw';\n    }\n    else if (capability.speed[0].number < 0 || capability.speed[1].number < 0) {\n      iconProperties.name = 'pan-continuous-ccw';\n    }\n  },\n  TiltContinuous(capability, iconProperties) {\n    if (capability.speed[0].number === 0 && capability.speed[1].number === 0) {\n      iconProperties.name = 'speed-stop';\n    }\n    else if (capability.speed[0].number > 0 || capability.speed[1].number > 0) {\n      iconProperties.name = 'tilt-continuous-cw';\n    }\n    else if (capability.speed[0].number < 0 || capability.speed[1].number < 0) {\n      iconProperties.name = 'tilt-continuous-ccw';\n    }\n  },\n  WheelSlot(capability, iconProperties) {\n    if (isAnimationGobo(capability)) {\n      iconProperties.name = 'animation-gobo';\n    }\n    else if (capability.wheelSlot[0] === capability.wheelSlot[1] && capability.wheelSlot[0].type !== 'Split') {\n      iconProperties.name = capability.wheelSlot[0].type === 'Color' ? 'color-changer' : capability.wheelSlot[0].type;\n      iconProperties.title += `, slot ${capability.slotNumber[0]} (${capability.wheelSlot[0].name})`;\n    }\n    else {\n      iconProperties.name = undefined;\n    }\n  },\n  WheelShake(capability, iconProperties) {\n    if (capability.wheelSlot && isAnimationGobo(capability)) {\n      iconProperties.name = 'animation-gobo';\n    }\n    else if (capability.wheelSlot && capability.wheelSlot[0] !== capability.wheelSlot[1]) {\n      iconProperties.name = undefined;\n    }\n    else {\n      iconProperties.name = capability.isShaking === 'slot' ? 'slot-shake' : 'wheel-shake';\n\n      if (capability.wheelSlot) {\n        iconProperties.title += `, slot ${capability.slotNumber[0]} (${capability.wheelSlot[0].name})`;\n      }\n    }\n  },\n  IrisEffect(capability, iconProperties) {\n    iconProperties.name = 'Iris';\n  },\n  FrostEffect(capability, iconProperties) {\n    iconProperties.name = 'Frost';\n  },\n  Fog(capability, iconProperties) {\n    specialIconFunctions.FogType(capability, iconProperties);\n  },\n  FogOutput(capability, iconProperties) {\n    iconProperties.name = 'smoke';\n  },\n  FogType(capability, iconProperties) {\n    iconProperties.name = capability.fogType === 'Haze' ? 'hazer' : 'smoke';\n  },\n  Speed(capability, iconProperties) {\n    if (!capability.speed) {\n      iconProperties.name = 'speed';\n    }\n    else if (capability.speed[0].number === 0 && capability.speed[1].number === 0) {\n      iconProperties.name = 'speed-stop';\n    }\n    else if (capability.speed[0].number > 0 || capability.speed[1].number > 0) {\n      iconProperties.name = 'speed-forward';\n    }\n    else {\n      iconProperties.name = 'speed-reverse';\n    }\n  },\n  Rotation(capability, iconProperties) {\n    if (capability.speed) {\n      specialIconFunctions.RotationSpeed(capability, iconProperties);\n    }\n    else {\n      iconProperties.name = 'rotation-angle';\n    }\n  },\n  RotationSpeed(capability, iconProperties) {\n    if (capability.speed[0].number === 0 && capability.speed[1].number === 0) {\n      iconProperties.name = 'speed-stop';\n    }\n    else if (capability.speed[0].number > 0 || capability.speed[1].number > 0) {\n      iconProperties.name = 'rotation-cw';\n    }\n    else {\n      iconProperties.name = 'rotation-ccw';\n    }\n  },\n  Generic(capability, iconProperties) {\n    iconProperties.name = 'other';\n  },\n};\n\n/**\n * @param {AbstractChannel} capability The capability to get an icon for.\n * @returns {object} Object containing the props to pass to <OflSvg />\n */\nfunction getIconProperties(capability) {\n  if (capability.colors !== null) {\n    return {\n      type: 'color-circle',\n      colors: capability.colors.allColors,\n      title: `Capability type: ${capability.type}, ${getColorDescription(capability)}`,\n    };\n  }\n\n  const iconProperties = {\n    type: 'fixture',\n    name: capability.type,\n    title: `Capability type: ${capability.type}`,\n  };\n\n  if (capability.isSoundControlled) {\n    iconProperties.name = 'sound-controlled';\n    iconProperties.title += ' (sound-controlled)';\n  }\n  else if (capability.type in specialIconFunctions) {\n    specialIconFunctions[capability.type](capability, iconProperties);\n  }\n  else if (/(?:Speed|Duration|Time)$/.test(capability.type)) {\n    specialIconFunctions.Speed(capability, iconProperties);\n  }\n  else if (capability.type.endsWith('Rotation')) {\n    specialIconFunctions.Rotation(capability, iconProperties);\n  }\n\n  return iconProperties;\n}\n\n/**\n * @param {Capability} capability The capability model object.\n * @returns {string | null} A string describing the colors of this capability, or null if it has no colors.\n */\nfunction getColorDescription(capability) {\n  if (capability.colors === null) {\n    return null;\n  }\n\n  if (capability.colors.isStep) {\n    const plural = capability.colors.allColors.length > 1 ? 'colors' : 'color';\n    const allColors = capability.colors.allColors.join(', ');\n    return `${plural}: ${allColors}`;\n  }\n\n  const startColors = capability.colors.startColors.join(', ');\n  const endColors = capability.colors.endColors.join(', ');\n  return `transition from ${startColors} to ${endColors}`;\n}\n</script>\n"
  },
  {
    "path": "ui/components/CategoryBadge.vue",
    "content": "<style lang=\"scss\" scoped>\n.category-badge {\n  display: inline-block;\n  padding: 4px 1.5ex 4px 1ex;\n  margin: 0 4px 4px 0;\n  background: theme-color(hover-background);\n  border-radius: 5000px; // see https://stackoverflow.com/a/18795153/451391\n\n  &:link,\n  &:visited {\n    color: theme-color(text-primary);\n    fill: theme-color(icon);\n  }\n\n  &:hover,\n  &:focus {\n    background-color: theme-color(active-background);\n  }\n\n  &.selected {\n    cursor: grab;\n    background-color: theme-color(blue-background-active);\n\n    &:link,\n    &:visited {\n      color: $primary-text-light;\n      fill: $icon-light;\n    }\n\n    &:hover,\n    &:focus {\n      background-color: $blue-300;\n    }\n  }\n\n  & > .icon {\n    width: 1.7em;\n    height: 1.7em;\n    margin-right: 4px;\n  }\n}\n</style>\n\n<script>\nimport { booleanProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    category: stringProp().required,\n    selected: booleanProp().withDefault(false),\n    selectable: booleanProp().withDefault(false),\n  },\n  emits: {\n    click: () => true,\n    focus: () => true,\n    blur: (event) => true,\n  },\n  render(createElement) {\n    const classes = {\n      'category-badge': true,\n      'selected': this.selected,\n    };\n    const children = [\n      createElement('OflSvg', {\n        props: {\n          type: 'fixture',\n          name: this.category,\n        },\n      }),\n      this.category,\n    ];\n\n    if (this.selectable) {\n      // <NuxtLink> is not cancellable, so we render a default <a> instead\n      return createElement('a', {\n        class: classes,\n        attrs: {\n          href: `#${encodeURIComponent(this.category)}`,\n        },\n        on: {\n          click: ($event) => {\n            this.$emit('click');\n            $event.preventDefault();\n          },\n          focus: () => {\n            this.$emit('focus');\n          },\n          blur: ($event) => {\n            this.$emit('blur', $event);\n          },\n        },\n      }, children);\n    }\n\n    return createElement('NuxtLink', {\n      class: classes,\n      props: {\n        to: `/categories/${encodeURIComponent(this.category)}`,\n      },\n    }, children);\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/ChannelTypeIcon.vue",
    "content": "<template>\n  <OflSvg v-bind=\"iconProperties\" />\n</template>\n\n<script>\nimport { instanceOfProp } from 'vue-ts-types';\nimport AbstractChannel from '../../lib/model/AbstractChannel.js';\nimport FineChannel from '../../lib/model/FineChannel.js';\nimport NullChannel from '../../lib/model/NullChannel.js';\nimport SwitchingChannel from '../../lib/model/SwitchingChannel.js';\n\nexport default {\n  props: {\n    channel: instanceOfProp(AbstractChannel).required,\n  },\n  computed: {\n    iconProperties() {\n      return getIconProperties(this.channel);\n    },\n  },\n};\n\nconst channelTypeIcons = {\n  'Multi-Color': 'color-changer',\n  'Fog': 'smoke',\n  'Intensity': 'dimmer',\n};\n\n/**\n * @param {AbstractChannel} channel The channel to get an icon for.\n * @returns {object} Object containing the props to pass to <OflSvg />\n */\nfunction getIconProperties(channel) {\n  if (channel instanceof NullChannel) {\n    return {\n      type: 'fixture',\n      name: 'NoFunction',\n      title: 'Channel type: NoFunction',\n    };\n  }\n\n  if (channel instanceof FineChannel) {\n    return getIconProperties(channel.coarseChannel);\n  }\n\n  if (channel instanceof SwitchingChannel) {\n    return {\n      type: 'fixture',\n      name: 'switching-channel',\n      title: 'Channel type: Switching Channel',\n    };\n  }\n\n  if (channel.type === 'Single Color') {\n    return {\n      type: 'color-circle',\n      name: channel.color,\n      title: `Channel type: Single Color, ${channel.color}`,\n    };\n  }\n\n  return {\n    type: 'fixture',\n    name: channelTypeIcons[channel.type] || channel.type,\n    title: `Channel type: ${channel.type}`,\n  };\n}\n</script>\n"
  },
  {
    "path": "ui/components/ClimateStrikeBanner.vue",
    "content": "<template>\n  <div v-if=\"isClimateStrike\" id=\"climate-strike-overlay\" class=\"climate-strike\">\n\n    <h1>\n      The Open Fixture Library joins the\n      <a :href=\"climateStrikeWebsite\">Global Climate Strike</a>\n      and is therefore not available today.\n    </h1>\n\n    <div>\n      <h2>Why should this affect me?</h2>\n      <p>\n        Because climate change affects everyone. Please read the\n        <a href=\"https://fridaysforfuture.org/take-action/reasons-to-strike/\">reasons to strike</a>.\n      </p>\n\n      <h2>When is OFL back again?</h2>\n      <p>\n        The global climate strike takes place on {{ strikeDateString }}.<br>\n        After that day, OFL is back to normal again.\n      </p>\n\n      <h2>Where can I learn more?</h2>\n      <p>Please refer to the <a href=\"https://fridaysforfuture.org/\">Fridays for Future website</a>.</p>\n\n      <div class=\"hashtags\">\n        <a v-for=\"hashtag of hashtags\" :key=\"hashtag\" :href=\"`https://mastodon.social/tags/${hashtag}`\">#{{ hashtag }}</a>\n      </div>\n    </div>\n\n  </div>\n  <div v-else-if=\"showClimateStrikeBanner\" id=\"climate-strike-banner\" class=\"climate-strike\">\n\n    We are joining the <a :href=\"climateStrikeWebsite\" target=\"_blank\" rel=\"noopener\">Global Climate Strike</a>,\n    so this website will not be available on {{ strikeDateString }}.<br>\n    Learn more at <a href=\"https://fridaysforfuture.org/\" target=\"_blank\" rel=\"noopener\">fridaysforfuture.org</a>.\n\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.climate-strike {\n  color: #ffffff;\n  text-align: center;\n\n  a {\n    color: #ffffff;\n    text-decoration: underline;\n    text-decoration-color: rgba(#ffffff, 60%);\n\n    &:hover,\n    &:focus {\n      opacity: 0.8;\n    }\n  }\n}\n\n#climate-strike-banner {\n  padding: 0.5em;\n  line-height: 1.7;\n  background: #1b7340;\n  border: 0.5em solid #1da64a;\n}\n\n#climate-strike-overlay {\n  position: fixed;\n  inset: 0;\n  z-index: 1000;\n  overflow: auto;\n  background: #1b7340;\n\n  h1 {\n    box-sizing: border-box;\n    padding: 0.5em 1em;\n    margin: 2.5em 0 1em;\n    font-weight: 700;\n    line-height: 1.2;\n    text-shadow: 0 0 5px rgba(#1b7340, 50%);\n    background: #1da64a;\n    transform: skewY(-2.5deg);\n\n    a {\n      display: block;\n      font-size: 1.8em;\n      text-transform: uppercase;\n    }\n\n    @media (max-width: $phone) {\n      font-size: 1.5em;\n    }\n  }\n\n  & > div {\n    h2 {\n      margin: 2em 10px 10px;\n      font-weight: 700;\n      line-height: 1.2;\n    }\n\n    p {\n      margin: 10px;\n    }\n  }\n\n  .hashtags {\n    margin: 3em 0 30px;\n    font-size: 1.5em;\n\n    a {\n      display: inline-block;\n      padding: 0 4px;\n      margin: 4px;\n      font-family: $font-stack-code;\n      font-weight: 400;\n    }\n  }\n}\n</style>\n\n<script>\nexport default {\n  data() {\n    return {\n      isClimateStrike: false,\n      showClimateStrikeBanner: false,\n      strikeDateString: '2023-09-15',\n      climateStrikeWebsite: 'https://fridaysforfuture.org/september15/',\n      hashtags: ['climatejustice', 'FridaysForFuture', 'climatestrike', 'EndFossilFuels', 'ClimateForChange'],\n    };\n  },\n  created() {\n    const strikeDate = new Date(this.strikeDateString);\n    strikeDate.setHours(0, 0, 0, 0);\n\n    const today = new Date();\n    today.setHours(0, 0, 0, 0);\n\n    const bannerStartDate = new Date(strikeDate);\n    bannerStartDate.setDate(strikeDate.getDate() - 14);\n\n    this.isClimateStrike = strikeDate.getTime() === today.getTime();\n    this.showClimateStrikeBanner = bannerStartDate.getTime() <= today.getTime() && today.getTime() < strikeDate.getTime();\n  },\n  mounted() {\n    if (this.isClimateStrike) {\n      document.documentElement.style.overflow = 'hidden';\n    }\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/ConditionalDetails.vue",
    "content": "<template>\n  <details v-if=\"$slots.default\">\n    <summary>\n      <slot name=\"summary\" />\n    </summary>\n\n    <slot />\n  </details>\n\n  <div v-else class=\"summary\">\n    <slot name=\"summary\" />\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\nsummary {\n  display: block;\n  cursor: pointer;\n  transition: background-color 0.2s;\n\n  &::-webkit-details-marker {\n    display: none;\n  }\n\n  &::after {\n    // chevron down\n    position: relative;\n    top: -0.2em;\n    left: 1.2ex;\n    display: inline-block;\n    width: 0.4em;\n    height: 0.4em;\n    vertical-align: middle;\n    content: \"\";\n    border-color: theme-color(icon);\n    border-style: solid;\n    border-width: 0.17em 0.17em 0 0;\n    transform: rotate(135deg);\n    transition-duration: 0.2s;\n    transition-property: transform, top, border-color;\n  }\n\n  &:hover,\n  &:focus {\n    outline: none;\n    background-color: theme-color(hover-background);\n\n    &::after {\n      border-color: theme-color(icon-hover);\n    }\n  }\n}\n\ndetails {\n  display: block; // needed for Edge\n\n  &[open] {\n    padding-bottom: 2ex;\n\n    & > summary::after {\n      // chevron up\n      top: 0;\n      transform: rotate(315deg);\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "ui/components/DownloadButton.vue",
    "content": "<template>\n  <div class=\"container\" :class=\"{ 'only-select-button': buttonStyle === `select` && !showHelp }\">\n    <!-- Display the download button as a select to make it work inside modals as well -->\n    <select\n      v-if=\"buttonStyle === `select`\"\n      @click=\"selectClicked = true\"\n      @keyup.enter=\"$event.target.blur()\"\n      @change=\"onDownloadSelectChange($event)\"\n      @blur=\"onDownloadSelectBlur($event)\">\n      <option value=\"\" disabled selected>{{ title }}</option>\n      <option v-for=\"plugin of exportPlugins\" :key=\"plugin.key\" :value=\"plugin.key\">{{ plugin.name }}</option>\n    </select>\n\n    <!-- Display the download button as hoverable div with real links in the dropdown -->\n    <div\n      v-else\n      class=\"download-button\"\n      :class=\"{ home: buttonStyle === `home` }\">\n      <a href=\"#\" class=\"title\" @click.prevent>{{ title }}</a>\n      <ul>\n        <li v-for=\"plugin of exportPlugins\" :key=\"plugin.key\">\n          <a\n            :href=\"`${baseLink}.${plugin.key}`\"\n            :title=\"`Download ${plugin.name} fixture definition${isSingle ? `` : `s`}`\"\n            rel=\"nofollow\"\n            @click=\"onDownloadButton($event, plugin.key)\">\n            {{ plugin.name }}\n          </a>\n        </li>\n      </ul>\n    </div>\n\n    <NuxtLink\n      v-if=\"showHelp\"\n      to=\"/about/plugins\"\n      :target=\"buttonStyle === `home` ? null : `_blank`\"\n      class=\"help-link\">\n      <OflSvg name=\"help-circle-outline\" /><span class=\"name\">Download instructions</span>\n    </NuxtLink>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.container {\n  margin: 0 0 1em;\n  text-align: center;\n\n  @media (width >= 650px) {\n    margin: 0;\n  }\n\n  &.only-select-button {\n    display: inline-block;\n    margin: 0;\n  }\n}\n\n.help-link {\n  display: inline-block;\n  margin-left: -1ex;\n  font-size: 0.9rem;\n  line-height: 1.2;\n  color: theme-color(text-secondary);\n  transition: opacity 0.15s;\n\n  .icon {\n    width: 1.2rem;\n    height: 1.2rem;\n    fill: theme-color(text-secondary);\n  }\n\n  .name {\n    margin-left: 0.5ex;\n    vertical-align: middle;\n  }\n\n  &:hover,\n  &:focus {\n    opacity: 0.7;\n  }\n}\n\nselect {\n  box-sizing: content-box;\n  display: inline-block;\n  width: 12.5ex;\n  height: 1.4em;\n  padding: 0.5em 3ex;\n  margin-top: 1ex;\n  margin-left: 1ex;\n  font-size: 0.9em;\n  font-weight: 700;\n  line-height: 1.4;\n  color: theme-color(button-secondary-text);\n  appearance: none;\n  cursor: pointer;\n  background: theme-color(button-secondary-background);\n  border-color: theme-color(button-secondary-border);\n  border-radius: 2px;\n  transition: 0.1s background-color;\n\n  &:not(:disabled):hover,\n  &:not(:disabled):focus {\n    background-color: theme-color(button-secondary-background-hover);\n  }\n}\n\n.download-button {\n  text-align: left;\n\n  & > .title {\n    box-sizing: border-box;\n    display: block;\n    width: 100%;\n    padding: 0.5ex 2ex;\n    font-weight: 700;\n    color: $primary-text-light;\n    cursor: pointer;\n    background: theme-color(orange-background);\n    border-radius: 2px;\n    box-shadow: 0 2px 2px rgba(#000000, 20%);\n    transition: border-radius 0.2s, background-color 0.2s;\n\n    // down arrow\n    &::before {\n      float: right;\n      display: block;\n      width: 0;\n      height: 0;\n      margin: 0.8em 0 0 1ex;\n      content: \"\";\n      border-color: currentcolor transparent transparent;\n      border-style: solid;\n      border-width: 0.4em 0.4em 0;\n    }\n  }\n\n  & > ul {\n    // just move the list to the left outside of the screen but don't hide it,\n    // to still allow screenreaders reading it\n    position: absolute;\n    top: 100%;\n    left: -9999px;\n    z-index: 90;\n    width: 100%;\n    padding: 0.7em 0;\n    margin: 0;\n    list-style: none;\n    background-color: theme-color(header-background);\n    border-radius: 0 0 2px 2px;\n    box-shadow: 0 2px 2px rgba(#000000, 20%);\n\n    & a {\n      display: block;\n      padding: 0.2ex 2ex;\n      color: theme-color(text-primary);\n      transition: background-color 0.2s;\n    }\n\n    & a:hover,\n    & a:focus {\n      outline: 0;\n      background-color: theme-color(hover-background);\n    }\n  }\n\n  // separate rule since unsupporting browsers skip the whole rule\n  &:focus-within > ul {\n    left: 0;\n  }\n\n  &:hover > ul,\n  & > .title:focus + ul,\n  & > .title:active + ul {\n    left: 0;\n  }\n\n  &:hover > .title,\n  & > .title:focus,\n  & > .title:active {\n    background: theme-color(orange-background-hover);\n    border-radius: 2px 2px 0 0;\n  }\n\n  &:focus-within > .title {\n    background: theme-color(orange-background-hover);\n    border-radius: 2px 2px 0 0;\n  }\n}\n</style>\n\n<script>\nimport { booleanProp, integerProp, objectProp, oneOfProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    // how many fixtures will be downloaded, if !isSingle?\n    fixtureCount: integerProp().withDefault(0),\n    // fixtures from the editor, not yet submitted\n    editorFixtures: objectProp().optional,\n    // the manufacturer key and fixture key of a submitted fixture\n    fixtureKey: stringProp().optional,\n    // the button style: default, 'home' or 'select'\n    buttonStyle: oneOfProp(['default', 'home', 'select']).withDefault('default'),\n    // show the help box\n    showHelp: booleanProp().withDefault(false),\n  },\n  data() {\n    return {\n      exportPlugins: [],\n      selectClicked: false,\n    };\n  },\n  async fetch() {\n    const plugins = await this.$axios.$get('/api/v1/plugins');\n    this.exportPlugins = plugins.exportPlugins.map(\n      (pluginKey) => ({\n        key: pluginKey,\n        name: plugins.data[pluginKey].name,\n      }),\n    );\n  },\n  computed: {\n    // returns whether we're handling only one single fixture here\n    // or all fixtures in a specific format\n    isSingle() {\n      return (this.editorFixtures && Object.keys(this.editorFixtures.fixtures).length === 1) || this.fixtureKey;\n    },\n    title() {\n      if (this.isSingle) {\n        return 'Download as…';\n      }\n\n      return `Download all ${this.fixtureCount} fixtures`;\n    },\n    baseLink() {\n      if (this.editorFixtures) {\n        return '/download-editor';\n      }\n\n      if (this.isSingle) {\n        return `/${this.fixtureKey}`;\n      }\n\n      return '/download';\n    },\n  },\n  methods: {\n    downloadDataAsFile(blob, filename = '') {\n      if (window.navigator.msSaveBlob) {\n        // IE workaround for \"HTML7007: One or more blob URLs were revoked by closing the blob for which they were created.\n        // These URLs will no longer resolve as the data backing the URL has been freed.\"\n        window.navigator.msSaveBlob(blob, filename);\n      }\n      else {\n        const URL = window.URL || window.webkitURL;\n        const downloadUrl = URL.createObjectURL(blob);\n\n        const anchorElement = document.createElement('a');\n\n        if (anchorElement.download === undefined) {\n          // non-HTML5 workaround\n          window.location = downloadUrl;\n        }\n        else {\n          anchorElement.href = downloadUrl;\n          anchorElement.download = filename;\n          document.body.append(anchorElement);\n          anchorElement.click();\n        }\n\n        // cleanup\n        setTimeout(() => {\n          URL.revokeObjectURL(downloadUrl);\n          anchorElement.remove();\n        }, 100);\n      }\n    },\n    async formattedDownload(pluginKey) {\n      // download the data as a file\n      // for more details, see https://stackoverflow.com/q/16086162/451391\n      const response = await this.$axios.post(\n        `${this.baseLink}.${pluginKey}`,\n        this.editorFixtures,\n        { responseType: 'blob' },\n      );\n\n      if (response.data.error) {\n        throw new Error(response.data.error);\n      }\n\n      let filename = '';\n      const disposition = response.headers['content-disposition'];\n      if (disposition && disposition.includes('attachment')) {\n        const filenameRegex = /filename[^\\n;=]*=(([\"']).*?\\2|[^\\n;]*)/;\n        const matches = filenameRegex.exec(disposition);\n        if (matches && matches[1]) {\n          filename = matches[1].replaceAll(/[\"']/g, '');\n        }\n      }\n\n      this.downloadDataAsFile(response.data, filename);\n    },\n    onDownloadButton(event, pluginKey) {\n      event.target.blur();\n\n      if (!this.editorFixtures) {\n        // default link target\n        return;\n      }\n\n      // download the (possibly not yet submitted) editor fixtures\n      event.preventDefault();\n      this.formattedDownload(pluginKey);\n    },\n    onDownloadSelectChange(event) {\n      if (this.selectClicked) {\n        event.target.blur(); // trigger download\n      }\n    },\n    onDownloadSelectBlur(event) {\n      if (event.target.value === '') {\n        // no plugin has been selected\n        return;\n      }\n\n      const pluginKey = event.target.value;\n\n      // reset the select value to make it feel more like a button\n      event.target.value = '';\n      this.selectClicked = false;\n\n      if (!this.editorFixtures) {\n        // download an already submitted fixture\n        window.open(`${this.baseLink}.${pluginKey}`);\n        return;\n      }\n\n      // download the (possibly not yet submitted) editor fixtures\n      this.formattedDownload(pluginKey);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/FixtureHeader.vue",
    "content": "<template>\n  <header class=\"fixture-header\">\n    <div class=\"title\">\n      <slot name=\"title\" />\n    </div>\n\n    <slot />\n  </header>\n</template>\n\n<style lang=\"scss\" scoped>\n.fixture-header ::v-deep .download-button {\n  position: relative;\n  display: block;\n}\n\n// move download button to the right\n@media (width >= 650px) {\n  .fixture-header {\n    display: flex;\n    flex-direction: row;\n    align-items: baseline;\n\n    & > .title {\n      flex-grow: 1;\n      flex-shrink: 1;\n    }\n\n    & ::v-deep .download-button {\n      flex-grow: 0;\n      flex-shrink: 0;\n      width: 14em;\n      margin: 1.5rem 0 0;\n\n      &.home {\n        width: 19em;\n\n        & .title {\n          font-size: 1.1em;\n        }\n      }\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "ui/components/HeaderBar.vue",
    "content": "<template>\n  <header>\n    <!-- eslint-disable vuejs-accessibility/click-events-have-key-events vuejs-accessibility/no-static-element-interactions -->\n    <nav @click=\"focusContent($event)\">\n      <div class=\"left-nav\">\n        <NuxtLink\n          class=\"home-logo\"\n          :class=\"{ 'hidden-by-search-field': searchFieldFocused }\"\n          to=\"/\"\n          exact\n          title=\"Home\">\n          Open Fixture Library\n        </NuxtLink>\n\n        <form action=\"/search\" @submit.prevent=\"search()\">\n          <div>\n            <input\n              v-model=\"searchQuery\"\n              type=\"search\"\n              name=\"q\"\n              placeholder=\"Search fixtures\"\n              aria-label=\"Search fixtures\"\n              @focus=\"searchFieldFocused = true\"\n              @blur=\"searchFieldFocused = false\">\n          </div>\n          <button class=\"icon-button\" type=\"submit\">\n            Search\n            <OflSvg name=\"magnify\" />\n          </button>\n        </form>\n      </div>\n\n      <div class=\"right-nav\">\n        <NuxtLink\n          to=\"/fixture-editor\"\n          title=\"Fixture editor\">\n          Add fixture\n        </NuxtLink>\n\n        <NuxtLink\n          to=\"/manufacturers\"\n          title=\"Browse fixtures by manufacturer\">\n          Manufacturers\n        </NuxtLink>\n\n        <NuxtLink\n          to=\"/categories\"\n          title=\"Browse fixtures by category\">\n          Categories\n        </NuxtLink>\n\n        <NuxtLink\n          to=\"/about\"\n          title=\"About the project\">\n          About\n        </NuxtLink>\n\n        <ClientOnly>\n          <ThemeSwitcher class=\"theme-switcher\" />\n        </ClientOnly>\n      </div>\n    </nav>\n  </header>\n</template>\n\n<style lang=\"scss\" scoped>\n@mixin home-logo-sizing($width, $padding) {\n  padding-left: calc(#{$width} + #{2 * $padding});\n\n  &::before {\n    background-size: calc(100% - #{2 * $padding}) auto;\n  }\n}\n\nheader {\n  position: fixed;\n  z-index: 100;\n  width: 100%;\n  text-align: center;\n  background: theme-color(header-background);\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 40%);\n  transition: background-color 0.3s;\n\n  nav {\n    display: flex;\n    flex-direction: row;\n    max-width: 1000px;\n    margin: 0 auto;\n  }\n\n  .right-nav {\n    flex-shrink: 0;\n    overflow: auto;\n    white-space: nowrap;\n  }\n\n  form {\n    display: flex;\n    flex-grow: 1;\n    align-items: center;\n    justify-content: center;\n  }\n\n  input {\n    width: 100%;\n    font-size: 1.05em;\n    line-height: 1.2;\n  }\n\n  button {\n    box-sizing: content-box;\n    margin-left: 4px;\n    font-size: 1.05em;\n    line-height: 1.2;\n  }\n\n  a,\n  .theme-switcher {\n    box-sizing: border-box;\n    display: inline-block;\n    height: 4.5em;\n    padding: 0 1ex;\n    margin: 0;\n    font-size: 1em;\n    line-height: 4.5em;\n    vertical-align: middle;\n    color: inherit;\n    text-decoration: none;\n    cursor: pointer;\n    background-color: transparent;\n    border: none;\n    fill: theme-color(icon);\n\n    &:active,\n    &:focus {\n      outline: 0;\n      background-color: theme-color(hover-background);\n    }\n\n    @include mobile-hover-emulation((\n      background-color: hover-background,\n      fill: icon-hover,\n    ));\n  }\n\n  .left-nav {\n    display: flex;\n    flex-grow: 1;\n    align-items: center;\n    justify-content: center;\n  }\n\n  .home-logo {\n    position: relative;\n    display: inline-block;\n    width: 0;\n    padding: 0;\n    overflow: hidden;\n    transition: background-color 0.2s, padding 0.2s;\n\n    @include home-logo-sizing(122px, 2ex);\n\n    &::before {\n      position: absolute;\n      inset: 0;\n      content: \"\";\n      background-image: url(\"~static/ofl-logo.svg\");\n      background-repeat: no-repeat;\n      background-position: center;\n    }\n  }\n}\n\n[data-theme=\"dark\"] header .home-logo::before {\n  filter: #{\"brightness(0.4) invert() brightness(0.9)\"};\n}\n\n@media (max-width: $tablet) {\n  header {\n    nav {\n      flex-wrap: wrap;\n\n      & > div {\n        flex-basis: 100%;\n      }\n    }\n\n    .home-logo {\n      @include home-logo-sizing(92px, 0.5ex);\n\n      height: 3em;\n      line-height: 3em;\n    }\n\n    form {\n      flex-grow: 0;\n      padding: 0 0.5ex;\n    }\n\n    .right-nav > a,\n    .right-nav > button {\n      height: 2.7em;\n      line-height: 2.7em;\n    }\n  }\n}\n\n@media (max-width: $phone) {\n  header {\n    .home-logo {\n      @include home-logo-sizing(82px, 0.5ex);\n\n      height: 2.8em;\n      line-height: 2.8em;\n\n      &.hidden-by-search-field {\n        padding: 0;\n      }\n    }\n\n    form,\n    form div {\n      flex-grow: 1;\n      flex-basis: 0;\n    }\n  }\n}\n</style>\n\n<script>\nimport ThemeSwitcher from './ThemeSwitcher.vue';\n\nexport default {\n  components: {\n    ThemeSwitcher,\n  },\n  emits: {\n    'focus-content': () => true,\n  },\n  data() {\n    return {\n      searchQuery: this.$router.history.current.query.q || '',\n      searchFieldFocused: false,\n    };\n  },\n  mounted() {\n    this.$router.afterEach(() => this.updateSearchQuery());\n  },\n  methods: {\n    updateSearchQuery() {\n      this.searchQuery = this.$router.history.current.query.q || '';\n    },\n    focusContent(event) {\n      if (event.target?.closest('a')) {\n        this.$emit('focus-content');\n      }\n    },\n    search() {\n      this.$router.push({\n        path: '/search',\n        query: {\n          q: this.searchQuery,\n        },\n      });\n      this.focusContent();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/HelpWantedDialog.vue",
    "content": "<template>\n  <A11yDialog\n    id=\"help-wanted-dialog\"\n    ref=\"dialog\"\n    :is-alert-dialog=\"state === `loading`\"\n    :shown=\"modelValue !== undefined\"\n    :title=\"title\"\n    @hide=\"onHide()\">\n\n    <form v-if=\"state === `ready` && modelValue !== undefined\" action=\"#\" @submit.prevent=\"onSubmit()\">\n      <LabeledValue\n        v-if=\"location !== null\"\n        key=\"location\"\n        :value=\"location\"\n        label=\"Location\" />\n\n      <LabeledValue\n        v-if=\"modelValue.helpWanted !== null\"\n        key=\"help-wanted\"\n        label=\"Problem description\">\n        <span v-html=\"modelValue.helpWanted\" />\n      </LabeledValue>\n\n      <LabeledInput name=\"message\" label=\"Message\">\n        <textarea v-model=\"message\" name=\"message\" />\n      </LabeledInput>\n\n      <LabeledInput\n        name=\"github-username\"\n        label=\"GitHub username\"\n        hint=\"If you want to be mentioned in the issue.\">\n        <input v-model=\"githubUsername\" type=\"text\" name=\"github-username\">\n      </LabeledInput>\n\n      <div class=\"button-bar right\">\n        <button :disabled=\"message === ``\" type=\"submit\" class=\"primary\">Send information</button>\n      </div>\n    </form>\n\n    <template v-else-if=\"state === `loading`\">\n      Uploading…\n    </template>\n\n    <template v-else-if=\"state === `success`\">\n      Your information was successfully uploaded to GitHub (see the <a :href=\"issueUrl\" target=\"_blank\" rel=\"noopener\">issue</a>). The fixture will be updated as soon as your information has been reviewed. Thank you for your contribution!\n\n      <div class=\"button-bar right\">\n        <a href=\"#\" class=\"button secondary\" @click.prevent=\"hide()\">Close</a>\n        <a :href=\"issueUrl\" class=\"button primary\" target=\"_blank\">See issue</a>\n      </div>\n    </template>\n\n    <template v-else-if=\"state === `error`\">\n      <span>Unfortunately, there was an error while uploading. Please copy the following data and manually submit it.</span>\n\n      <textarea :value=\"errorData\" readonly />\n\n      <div class=\"button-bar right\">\n        <a href=\"#\" class=\"button secondary\" @click.prevent=\"hide()\">Close</a>\n        <a :href=\"mailtoUrl\" class=\"button secondary\" target=\"_blank\">Send email</a>\n        <a\n          href=\"https://github.com/OpenLightingProject/open-fixture-library/issues/new\"\n          class=\"button primary\"\n          target=\"_blank\"\n          rel=\"noopener\">\n          Create issue on GitHub\n        </a>\n      </div>\n    </template>\n\n  </A11yDialog>\n</template>\n\n<script>\nimport { objectProp, stringProp } from 'vue-ts-types';\nimport A11yDialog from './A11yDialog.vue';\nimport LabeledInput from './LabeledInput.vue';\nimport LabeledValue from './LabeledValue.vue';\n\nexport default {\n  components: {\n    A11yDialog,\n    LabeledInput,\n    LabeledValue,\n  },\n  model: {\n    prop: 'model-value',\n    event: 'update:model-value',\n  },\n  props: {\n    type: stringProp().required,\n    modelValue: objectProp().optional,\n  },\n  emits: {\n    'update:model-value': (value) => true,\n  },\n  data: () => {\n    return {\n      state: 'ready',\n      message: '',\n      githubUsername: '',\n      issueUrl: null,\n      error: null,\n    };\n  },\n  computed: {\n    title() {\n      if (this.state === 'loading') {\n        return 'Sending your message…';\n      }\n\n      if (this.state === 'success') {\n        return 'Message sent';\n      }\n\n      if (this.state === 'error') {\n        return 'Failed to send message';\n      }\n\n      if (this.type === 'plugin') {\n        return 'Improve plugin';\n      }\n\n      return 'Improve fixture';\n    },\n    location() {\n      if (this.type === 'capability') {\n        const capability = this.modelValue;\n        const channel = capability._channel;\n        return `Channel \"${channel.key}\" → Capability \"${capability.name}\" (${capability.rawDmxRange})`;\n      }\n\n      return null;\n    },\n    fixture() {\n      if (this.type === 'fixture') {\n        return this.modelValue;\n      }\n\n      if (this.type === 'capability') {\n        return this.modelValue._channel.fixture;\n      }\n\n      return null;\n    },\n    sendObject() {\n      const sendObject = {\n        type: this.type,\n        location: this.location,\n        helpWanted: this.modelValue.helpWanted,\n        message: this.message,\n        githubUsername: this.githubUsername === '' ? null : this.githubUsername,\n      };\n\n      if (this.type === 'plugin') {\n        sendObject.context = this.modelValue.key;\n      }\n      else {\n        const manufacturerKey = this.fixture.manufacturer.key;\n        const fixtureKey = this.fixture.key;\n\n        sendObject.context = `${manufacturerKey}/${fixtureKey}`;\n      }\n\n      return sendObject;\n    },\n    errorData() {\n      return `${JSON.stringify(this.sendObject, null, 2)}\\n\\n${this.error}`;\n    },\n    mailtoUrl() {\n      const subject = `Feedback for ${this.sendObject.type} '${this.sendObject.modelValue}'`;\n\n      const mailBodyData = {\n        'Problem location': this.location,\n        'Problem description': this.modelValue.helpWanted,\n        'Message': this.message,\n      };\n\n      const body = Object.entries(mailBodyData).filter(\n        ([key, value]) => value !== null,\n      ).map(([key, value]) => {\n        const separator = value.includes('\\n') ? '\\n' : ' ';\n        return `${key}:${separator}${value}`;\n      }).join('\\n');\n\n      return `mailto:flo@open-fixture-library.org?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;\n    },\n  },\n  mounted() {\n    if (localStorage) {\n      this.githubUsername = localStorage.getItem('prefillGithubUsername') || '';\n    }\n  },\n  methods: {\n    async onSubmit() {\n      this.state = 'loading';\n      localStorage.setItem('prefillGithubUsername', this.githubUsername);\n\n      try {\n        const response = await this.$axios.post('/api/v1/submit-feedback', this.sendObject);\n\n        if (response.data.error) {\n          throw new Error(response.data.error);\n        }\n\n        this.issueUrl = response.data.issueUrl;\n        this.state = 'success';\n      }\n      catch (error) {\n        console.error('There was a problem with the request.', error);\n        this.error = error.message;\n        this.state = 'error';\n      }\n    },\n    hide() {\n      this.$refs.dialog.$emit('hide');\n    },\n    onHide() {\n      if (this.state === 'success') {\n        this.message = '';\n      }\n\n      this.state = 'ready';\n      this.issueUrl = null;\n      this.error = null;\n      this.$emit('update:model-value', undefined);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/HelpWantedMessage.vue",
    "content": "<template>\n  <section class=\"help-wanted\">\n    <div class=\"information\">\n      <OflSvg name=\"comment-question-outline\" title=\"Help wanted!\" />\n      <strong v-if=\"title\">{{ title }} </strong>\n      <span v-html=\"description\" />\n    </div>\n\n    <div class=\"actions\">\n      <a\n        href=\"#\"\n        class=\"only-js\"\n        @click.prevent=\"$emit(`help-wanted-clicked`, { type, context })\">\n        <OflSvg name=\"comment-alert\" class=\"left\" />\n        <span>Send information</span>\n      </a>\n      <a\n        href=\"https://github.com/OpenLightingProject/open-fixture-library/issues?q=is%3Aopen+is%3Aissue+label%3Abug\"\n        class=\"no-js\"\n        rel=\"nofollow\">\n        <OflSvg name=\"bug\" class=\"left\" />\n        <span>Create issue on GitHub</span>\n      </a>\n      <a :href=\"mailtoUrl\" class=\"no-js\">\n        <OflSvg name=\"email\" class=\"left\" />\n        <span>Send email</span>\n      </a>\n    </div>\n  </section>\n</template>\n\n<style lang=\"scss\" scoped>\n.help-wanted {\n  position: relative;\n  min-height: 32px;\n  padding: 0;\n  margin: 1ex 0;\n  line-height: 1.6;\n  background: theme-color(yellow-background);\n  border-radius: 2px;\n}\n\n.information {\n  $icon-width: 1.4em;\n  $text-margin: 0.5em;\n\n  padding: 0.6em 0.7em 0.6em (0.7em + $icon-width + $text-margin);\n  border-bottom: 2px solid theme-color(yellow-background-hover);\n\n  & > .icon {\n    float: left;\n    padding-right: $text-margin;\n    margin-top: 0.2em;\n    margin-left: -$icon-width - $text-margin;\n  }\n}\n\n.actions {\n  display: flex;\n  flex-flow: row wrap;\n  justify-content: space-evenly;\n  font-size: 90%;\n\n  a {\n    box-sizing: border-box;\n    display: inline-block;\n    flex-grow: 1;\n    flex-basis: 10em;\n    width: 100%;\n    padding: 0.4em 0.6em;\n    color: theme-color(text-primary);\n    text-align: center;\n\n    &:hover,\n    &:focus {\n      outline: 0;\n      background: theme-color(yellow-background-hover);\n      fill: theme-color(text-primary);\n    }\n\n    & > .icon {\n      margin-right: 1ex;\n    }\n  }\n}\n</style>\n\n<script>\nimport { objectProp, oneOfProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    type: oneOfProp(['fixture', 'capability', 'plugin']).required,\n    context: objectProp().required,\n  },\n  emits: {\n    'help-wanted-clicked': (payload) => true,\n  },\n  computed: {\n    location() {\n      if (this.type === 'capability') {\n        const capability = this.context;\n        const channel = capability._channel;\n        return `Channel \"${channel.name}\" → Capability \"${capability.name}\" (${capability.rawDmxRange})`;\n      }\n\n      return null;\n    },\n\n    fixture() {\n      if (this.type === 'fixture') {\n        return this.context;\n      }\n\n      if (this.type === 'capability') {\n        return this.context._channel.fixture;\n      }\n\n      return null;\n    },\n\n    title() {\n      if (this.type === 'fixture') {\n        return 'You can help to improve this fixture definition!';\n      }\n\n      if (this.type === 'plugin') {\n        return 'You can help to improve this plugin!';\n      }\n\n      return null;\n    },\n\n    description() {\n      if (this.type === 'fixture') {\n        if (this.fixture.helpWanted === null) {\n          return 'Specific questions are included in the capabilities below.';\n        }\n\n        if (this.fixture.isCapabilityHelpWanted) {\n          return `${this.fixture.helpWanted} Further questions are included in the capabilities below.`;\n        }\n      }\n\n      return this.context.helpWanted;\n    },\n\n    mailtoUrl() {\n      const subject = this.fixture\n        ? `Feedback for fixture '${this.fixture.manufacturer.key}/${this.fixture.key}'`\n        : `Feedback for ${this.type} '${this.context.key}'`;\n\n      const bodyLines = [];\n      if (this.location) {\n        bodyLines.push(`Problem location: ${this.location}`);\n      }\n      if (this.context.helpWanted) {\n        bodyLines.push(`Problem description: ${this.context.helpWanted}`);\n      }\n\n      const body = bodyLines.join('\\n');\n\n      return `mailto:flo@open-fixture-library.org?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/LabeledInput.vue",
    "content": "<template>\n  <Validate\n    v-if=\"formstate\"\n    :state=\"formstate\"\n    :custom=\"customValidators\"\n    :tag=\"multipleInputs ? 'div' : 'label'\">\n\n    <LabeledValue :name=\"name\">\n      <template #label>\n        <template v-if=\"label\">{{ label }}</template>\n        <slot name=\"label\" />\n      </template>\n\n      <slot />\n\n      <div\n        v-show=\"fieldState.$touched || fieldState.$submitted\"\n        class=\"error-message\">\n        <div v-if=\"isSelectField && fieldErrors.required\">Please select a value.</div>\n        <div v-else-if=\"fieldErrors.required\">Please fill out this field.</div>\n\n        <!-- custom validators -->\n        <div v-else-if=\"fieldErrors[`complete-range`]\">Please fill out both start and end of the range.</div>\n        <div v-else-if=\"fieldErrors[`valid-range`]\">The start value of a range must not be greater than its end.</div>\n        <div v-else-if=\"fieldErrors[`categories-not-empty`]\">Please select at least one category.</div>\n        <div v-else-if=\"fieldErrors[`complete-dimensions`]\">Please fill out all dimensions.</div>\n        <div v-else-if=\"fieldErrors[`start-with-uppercase-or-number`]\">Please start with an uppercase letter or a number.</div>\n        <div v-else-if=\"fieldErrors[`no-manufacturer-name`]\">Don't include the manufacturer name.</div>\n        <div v-else-if=\"fieldErrors[`no-mode-name`]\">Don't include the word \"mode\", it is appended automatically.</div>\n        <div v-else-if=\"fieldErrors[`no-fine-channel-name`]\">Don't create fine channels manually, set the channel resolution below instead.</div>\n        <div v-else-if=\"fieldErrors[`entity-complete`]\">Please fill out this field.</div>\n        <div v-else-if=\"fieldErrors[`entities-have-same-units`]\">Please use the same unit or select a keyword for both entities.</div>\n        <div v-else-if=\"fieldErrors[`valid-color-hex-list`]\">Please enter a list of #rrggbb (red, green, blue) hex codes.</div>\n        <div v-else-if=\"fieldErrors[`max-file-size`]\">The file size must be less or equal to {{ fieldState.$attrs[`max-file-size`] }}.</div>\n        <div v-else-if=\"fieldErrors[`animation-gobo-end-without-start`]\">AnimationGoboEnd slots must only be used directly after AnimationGoboStart slots.</div>\n        <div v-else-if=\"fieldErrors[`must-be-animation-gobo-end`]\">An AnimationGoboEnd slot must be used directly after an AnimationGoboStart slot.</div>\n\n        <!-- general validators -->\n        <div v-else-if=\"fieldErrors.number\">Please enter a number.</div>\n        <div v-else-if=\"fieldErrors[`data-exclusive-minimum`]\">Please enter a value greater than {{ fieldState.$attrs[`data-exclusive-minimum`] }}.</div>\n        <div v-else-if=\"fieldErrors.min \">Please enter a value greater or equal to {{ fieldState.$attrs.min }}.</div>\n        <div v-else-if=\"fieldErrors[`data-exclusive-maximum`]\">Please enter a value less than {{ fieldState.$attrs[`data-exclusive-maximum`] }}.</div>\n        <div v-else-if=\"fieldErrors.max \">Please enter a value less or equal to {{ fieldState.$attrs.max }}.</div>\n        <div v-else-if=\"fieldErrors.step && Number(fieldState.$attrs.step) === 1\">Please enter a whole number.</div>\n        <div v-else-if=\"fieldErrors.step\">Please enter a multiple of {{ fieldState.$attrs.step }}.</div>\n        <div v-else-if=\"fieldErrors.email\">Please enter an email address.</div>\n        <div v-else-if=\"fieldErrors.url\">Please enter a URL.</div>\n        <div v-else-if=\"fieldErrors.pattern\">\n          Has to match pattern<span v-if=\"fieldState.$attrs.title\">: {{ fieldState.$attrs.title }}</span>.\n        </div>\n      </div>\n\n      <div v-if=\"hint\" class=\"hint\">{{ hint }}</div>\n\n    </LabeledValue>\n\n  </Validate>\n\n  <label v-else>\n    <LabeledValue>\n      <template #label>\n        <template v-if=\"label\">{{ label }}</template>\n        <slot name=\"label\" />\n      </template>\n\n      <slot />\n      <div v-if=\"hint\" class=\"hint\">{{ hint }}</div>\n    </LabeledValue>\n  </label>\n</template>\n\n<script>\nimport { booleanProp, objectProp, stringProp } from 'vue-ts-types';\nimport LabeledValue from './LabeledValue.vue';\n\nexport default {\n  components: {\n    LabeledValue,\n  },\n  props: {\n    /** The internal name of the input field, used for state tracking. */\n    name: stringProp().optional, // TODO: make this required\n    /** The visible label text for the input. */\n    label: stringProp().optional,\n    /** Helper text displayed below the input. */\n    hint: stringProp().optional,\n    /** The validation state object from the parent form. */\n    formstate: objectProp().optional, // TODO: make this required\n    /** Object containing custom validation functions. */\n    customValidators: objectProp().optional,\n    /**\n     * Whether this component wraps multiple inputs.\n     * If true, renders a `div` instead of a `label` to avoid browser issues (e.g., Safari).\n     */\n    multipleInputs: booleanProp().withDefault(false),\n  },\n  computed: {\n    /**\n     * Retrieves the specific state object for this field from the global formstate.\n     * Handles nested fields and prevents access errors if formstate is not yet initialized.\n     * @returns {object|null} The field's state object or null if not found.\n     */\n    fieldState() {\n      if (!this.formstate) {\n        return null;\n      }\n\n      if (this.formstate.$error[this.name]) {\n        return this.formstate[this.name];\n      }\n\n      const subFieldNames = Object.keys(this.formstate).filter(\n        (subFieldName) => subFieldName.startsWith(this.name),\n      );\n\n      for (const subFieldName of subFieldNames) {\n        if (this.formstate.$error[subFieldName]) {\n          const fieldState = this.formstate[subFieldName];\n\n          if (fieldState.$touched || fieldState.$submitted) {\n            return fieldState;\n          }\n        }\n      }\n\n      return {};\n    },\n    fieldErrors() {\n      if (!('$valid' in this.fieldState) || this.fieldState.$valid) {\n        return {};\n      }\n\n      return this.fieldState.$error;\n    },\n    isSelectField() {\n      return this.name === 'manufacturerKey' || this.name === 'plugin' || /^capability.*?-(?:type|shutterEffect|color|effectPreset|fogType)$/.test(this.name);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/LabeledValue.vue",
    "content": "<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -- use more accessible way of highlighting -->\n\n<template>\n  <section\n    :class=\"name\"\n    @focusin=\"$emit('focusin', $event)\"\n    @focusout=\"$emit('focusout', $event)\"\n    @mouseover=\"$emit('mouseover', $event)\"\n    @mouseout=\"$emit('mouseout', $event)\">\n    <div class=\"label\">\n      <template v-if=\"label\">{{ label }}</template>\n      <slot name=\"label\" />\n    </div>\n    <div class=\"value\">\n      <template v-if=\"value\">{{ value }}</template>\n      <slot />\n    </div>\n  </section>\n</template>\n\n<style lang=\"scss\" scoped>\nsection {\n  padding: 0.5ex 0;\n\n  & > .label {\n    color: theme-color(text-secondary);\n  }\n}\n\n// move labels left of values\n@media (min-width: $phone-landscape) {\n  section {\n    display: flex;\n    flex-flow: row nowrap;\n    align-items: flex-start;\n\n    & > .label {\n      flex: 0 0 10rem;\n    }\n\n    & > .value {\n      // take up the remaining space\n      flex-grow: 1;\n      flex-shrink: 1;\n      min-width: 0;\n    }\n  }\n}\n</style>\n\n<script>\nimport { stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    name: stringProp().optional,\n    label: stringProp().optional,\n    value: stringProp().optional,\n  },\n  emits: {\n    focusin: (event) => true,\n    focusout: (event) => true,\n    mouseover: (event) => true,\n    mouseout: (event) => true,\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/PropertyInputBoolean.vue",
    "content": "<template>\n  <span>\n    <input\n      ref=\"input\"\n      v-model=\"localValue\"\n      type=\"checkbox\"\n      :required=\"required\"\n      :name=\"name\">\n    {{ label }}\n  </span>\n</template>\n\n<script>\nimport { booleanProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    required: booleanProp().withDefault(false),\n    value: booleanProp().withDefault(false),\n    name: stringProp().required,\n    label: stringProp().required,\n  },\n  emits: {\n    input: (value) => true,\n  },\n  computed: {\n    localValue: {\n      get() {\n        return this.value;\n      },\n      set(newValue) {\n        this.$emit('input', newValue ? true : null);\n      },\n    },\n  },\n  methods: {\n    /** @public */\n    focus() {\n      this.$refs.input.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/PropertyInputDimensions.vue",
    "content": "<template>\n  <span class=\"dimensions\">\n    <Validate :state=\"formstate\" tag=\"span\">\n      <PropertyInputNumber\n        ref=\"xInput\"\n        v-model=\"x\"\n        :name=\"`${name}-x`\"\n        :schema-property=\"schemaProperty.items\"\n        :required=\"required || dimensionsSpecified\"\n        :hint=\"hints[0]\"\n        @focus=\"onFocus()\"\n        @blur=\"onBlur($event)\" />\n    </Validate>\n    &times;\n    <Validate :state=\"formstate\" tag=\"span\">\n      <PropertyInputNumber\n        v-model=\"y\"\n        :name=\"`${name}-y`\"\n        :schema-property=\"schemaProperty.items\"\n        :required=\"required || dimensionsSpecified\"\n        :hint=\"hints[1]\"\n        @focus=\"onFocus()\"\n        @blur=\"onBlur($event)\" />\n    </Validate>\n    &times;\n    <Validate :state=\"formstate\" tag=\"span\">\n      <PropertyInputNumber\n        v-model=\"z\"\n        :name=\"`${name}-z`\"\n        :schema-property=\"schemaProperty.items\"\n        :required=\"required || dimensionsSpecified\"\n        :hint=\"hints[2]\"\n        @focus=\"onFocus()\"\n        @blur=\"onBlur($event)\" />\n    </Validate>\n    {{ unit }}\n  </span>\n</template>\n\n<script>\nimport { arrayProp, booleanProp, objectProp, stringProp } from 'vue-ts-types';\nimport PropertyInputNumber from './PropertyInputNumber.vue';\n\nexport default {\n  components: {\n    PropertyInputNumber,\n  },\n  model: {\n    prop: 'model-value',\n    event: 'update:model-value',\n  },\n  props: {\n    modelValue: arrayProp().withDefault(null),\n    hints: arrayProp().withDefault(() => ['x', 'y', 'z']),\n    schemaProperty: objectProp().required,\n    unit: stringProp().optional,\n    required: booleanProp().withDefault(false),\n    name: stringProp().required,\n    formstate: objectProp().required,\n  },\n  emits: {\n    'update:model-value': (dimensions) => true,\n    'focus': () => true,\n    'blur': () => true,\n    'vf:validate': (validationData) => true,\n  },\n  data() {\n    return {\n      validationData: {\n        'complete-dimensions': '',\n      },\n    };\n  },\n  computed: {\n    x: {\n      get() {\n        return this.modelValue ? this.modelValue[0] : null;\n      },\n      set(xInput) {\n        this.$emit('update:model-value', getDimensionsArray(xInput, this.y, this.z));\n      },\n    },\n    y: {\n      get() {\n        return this.modelValue ? this.modelValue[1] : null;\n      },\n      set(yInput) {\n        this.$emit('update:model-value', getDimensionsArray(this.x, yInput, this.z));\n      },\n    },\n    z: {\n      get() {\n        return this.modelValue ? this.modelValue[2] : null;\n      },\n      set(zInput) {\n        this.$emit('update:model-value', getDimensionsArray(this.x, this.y, zInput));\n      },\n    },\n    dimensionsSpecified() {\n      return this.modelValue !== null;\n    },\n  },\n  mounted() {\n    this.$emit('vf:validate', this.validationData);\n  },\n  methods: {\n    onFocus() {\n      this.$emit('focus');\n    },\n    onBlur(event) {\n      if (!(event.target && event.relatedTarget) || event.target.closest('.dimensions') !== event.relatedTarget.closest('.dimensions')) {\n        this.$emit('blur');\n      }\n    },\n\n    /** @public */\n    focus() {\n      this.$refs.xInput.focus();\n    },\n  },\n};\n\n/**\n * @param {number | null} x X value of the dimensions array or null.\n * @param {number | null} y Y value of the dimensions array or null.\n * @param {number | null} z Z value of the dimensions array or null.\n * @returns {[number, number, number] | null} Dimensions array with the inputs or null if all inputs were null.\n */\nfunction getDimensionsArray(x, y, z) {\n  if (x === null && y === null && z === null) {\n    return null;\n  }\n\n  return [x, y, z];\n}\n</script>\n"
  },
  {
    "path": "ui/components/PropertyInputEntity.vue",
    "content": "<template>\n  <span class=\"entity-input\" :class=\"{ 'has-number': hasNumber, wide }\">\n\n    <Validate v-if=\"hasNumber\" tag=\"span\">\n      <PropertyInputNumber\n        ref=\"input\"\n        v-model=\"selectedNumber\"\n        class=\"property-input-number\"\n        :schema-property=\"units[selectedUnit].numberSchema\"\n        required\n        :minimum=\"minNumber === undefined ? `invalid` : minNumber\"\n        :maximum=\"maxNumber === undefined ? `invalid` : maxNumber\"\n        :name=\"name ? `${name}-number` : null\"\n        @focus=\"onFocus()\"\n        @blur=\"onBlur($event)\" />\n    </Validate>\n\n    <select\n      ref=\"select\"\n      v-model=\"selectedUnit\"\n      :required=\"required\"\n      :class=\"{ empty: selectedUnit === `` }\"\n      @input=\"unitSelected()\"\n      @focus=\"onFocus()\"\n      @blur=\"onBlur($event)\">\n\n      <option :disabled=\"required\" value=\"\">unset</option>\n\n      <optgroup v-if=\"enumValues.length > 0\" label=\"Keywords\">\n        <option\n          v-for=\"enumValue of enumValues\"\n          :key=\"enumValue\"\n          :value=\"enumValue\">{{ enumValue }}</option>\n      </optgroup>\n\n      <optgroup v-if=\"Object.keys(units).length > 0\" label=\"Units\">\n        <option\n          v-for=\"({ displayString }, unitName) of units\"\n          :key=\"unitName\"\n          :value=\"unitName\">{{ displayString }}</option>\n      </optgroup>\n\n    </select>\n  </span>\n</template>\n\n<style lang=\"scss\" scoped>\n.entity-input {\n  & select {\n    width: 20ex;\n  }\n\n  &.wide select {\n    width: 30ex;\n  }\n\n  &.has-number {\n    & select {\n      width: 10ex;\n    }\n\n    & .property-input-number {\n      width: 9ex;\n      margin-right: 1ex;\n    }\n  }\n\n  &.wide.has-number {\n    & select {\n      width: 15ex;\n    }\n\n    & .property-input-number {\n      width: 14ex;\n      margin-right: 1ex;\n    }\n  }\n}\n</style>\n\n<script>\nimport { anyProp, booleanProp, numberProp, objectProp, stringProp } from 'vue-ts-types';\nimport { unitsSchema } from '../../lib/schema-properties.js';\nimport PropertyInputNumber from './PropertyInputNumber.vue';\n\nexport default {\n  components: {\n    PropertyInputNumber,\n  },\n  props: {\n    schemaProperty: objectProp().required,\n    required: booleanProp().withDefault(false),\n    value: anyProp().withDefault(''),\n    associatedEntity: anyProp().optional,\n    minNumber: numberProp().optional,\n    maxNumber: numberProp().optional,\n    name: stringProp().required,\n    wide: booleanProp().withDefault(false),\n  },\n  emits: {\n    'input': (value) => true,\n    'focus': () => true,\n    'blur': () => true,\n    'unit-selected': (unitString) => true,\n    'vf:validate': (validationData) => true,\n  },\n  data() {\n    return {\n      validationData: {\n        'entity-complete': '',\n        'entities-have-same-units': '',\n      },\n    };\n  },\n  computed: {\n    subSchemas() {\n      return this.schemaProperty.oneOf || [this.schemaProperty];\n    },\n    enumValues() {\n      const enumSubSchema = this.subSchemas.find((subSchema) => 'enum' in subSchema);\n\n      return enumSubSchema ? enumSubSchema.enum : [];\n    },\n    unitNames() {\n      return this.subSchemas.filter(\n        (subSchema) => '$ref' in subSchema && subSchema.$ref.includes('#/units/'),\n      ).map(\n        (subSchema) => subSchema.$ref.replace(/^(?:definitions\\.json)?#\\/units\\//, ''),\n      );\n    },\n    units() {\n      const units = {};\n      for (const unitName of this.unitNames) {\n        const unitSchema = unitsSchema[unitName];\n\n        const unitString = 'pattern' in unitSchema ? parseUnitFromPattern(unitSchema.pattern) : '';\n        const numberSchema = 'pattern' in unitSchema ? unitsSchema.number : unitSchema;\n\n        units[unitName] = {\n          unitString,\n          displayString: getUnitDisplayString(unitString),\n          numberSchema,\n        };\n      }\n\n      return units;\n    },\n    selectedUnit: {\n      get() {\n        return getSelectedUnit(this.value, this.enumValues, this.unitNames, this.units);\n      },\n      set(newUnit) {\n        if (this.enumValues.includes(newUnit) || newUnit === '') {\n          this.update(newUnit);\n        }\n        else if (this.units[newUnit].unitString === '') {\n          if (this.selectedNumber === '') {\n            this.update('[no unit]');\n          }\n          else {\n            this.update(Number.parseFloat(this.selectedNumber));\n          }\n          this.$emit('unit-selected', '[no unit]');\n        }\n        else {\n          this.update(this.selectedNumber + this.units[newUnit].unitString);\n          this.$emit('unit-selected', this.units[newUnit].unitString);\n        }\n      },\n    },\n    hasNumber() {\n      return hasNumber(this.selectedUnit, this.enumValues);\n    },\n    selectedNumber: {\n      get() {\n        if (typeof this.value !== 'string') {\n          return this.value;\n        }\n\n        const number = Number.parseFloat(this.value.replace(this.selectedUnit, ''));\n\n        return Number.isNaN(number) ? '' : number;\n      },\n      set(newNumber) {\n        if (newNumber === null || newNumber === 'invalid') {\n          newNumber = '';\n        }\n\n        if (this.units[this.selectedUnit].unitString === '') {\n          if (newNumber === '') {\n            this.update('[no unit]');\n          }\n          else {\n            this.update(Number.parseFloat(newNumber));\n          }\n        }\n        else {\n          this.update(newNumber + this.units[this.selectedUnit].unitString);\n        }\n      },\n    },\n\n    /**\n     * Used by vue-form's `entities-have-same-units` validation rule.\n     * @public\n     * @returns {boolean} True if this and the associated entity have the same unit.\n     */\n    hasSameUnit() {\n      if (!this.associatedEntity) {\n        return true;\n      }\n\n      const otherFieldSelectedUnit = getSelectedUnit(this.associatedEntity, this.enumValues, this.unitNames, this.units);\n\n      if (!this.hasNumber && !hasNumber(otherFieldSelectedUnit, this.enumValues)) {\n        return true;\n      }\n\n      return this.selectedUnit === otherFieldSelectedUnit;\n    },\n  },\n  mounted() {\n    this.$emit('vf:validate', this.validationData);\n  },\n  methods: {\n    /** @public */\n    focus() {\n      const focusField = this.$refs.input ?? this.$refs.select;\n      focusField.focus();\n    },\n    update(newValue) {\n      this.$emit('input', newValue);\n    },\n\n    /**\n     * Called by {@link EditorProportionalPropertySwitcher}\n     * @param {string} newUnitString The unit string to set.\n     * @public\n     */\n    setUnitString(newUnitString) {\n      if (newUnitString === '[no unit]') {\n        newUnitString = '';\n      }\n\n      this.selectedUnit = Object.keys(this.units).find(\n        (unitName) => this.units[unitName].unitString === newUnitString,\n      );\n    },\n    async unitSelected() {\n      // wait for data to change locally (emits event)\n      await this.$nextTick();\n\n      // wait for new value from props\n      await this.$nextTick();\n\n      this.focus();\n    },\n    onFocus() {\n      this.$emit('focus');\n    },\n    onBlur(event) {\n      if (!(event.target && event.relatedTarget) || event.target.closest('.entity-input') !== event.relatedTarget.closest('.entity-input')) {\n        this.$emit('blur');\n      }\n    },\n  },\n};\n\n/**\n * @param {string} pattern The pattern string to parse.\n * @returns {string} The unit string.\n */\nfunction parseUnitFromPattern(pattern) {\n  if (!pattern.endsWith('$')) {\n    throw new Error(`Pattern does not end with '$': ${pattern}`);\n  }\n\n  const lastNumberPartIndex = Math.max(pattern.lastIndexOf(')'), pattern.lastIndexOf('?'));\n  return pattern.slice(lastNumberPartIndex + 1, -1).replaceAll('\\\\', '');\n}\n\n/**\n * @param {string} unitString The unit string, as required by the schema.\n * @returns {string} The unitString if it is not empty, `number` otherwise.\n */\nfunction getUnitDisplayString(unitString) {\n  if (unitString === '') {\n    return 'number';\n  }\n\n  return unitString.replace('^2', '²').replace('^3', '³');\n}\n\n/**\n * @param {string | number | null} value The value to get the unit from.\n * @param {string[]} enumValues List of allowed keywords.\n * @param {string[]} unitNames List of names of allowed units.\n * @param {Record<string, object>} units Unit data by unit name.\n * @returns {string} The name of value's unit.\n */\nfunction getSelectedUnit(value, enumValues, unitNames, units) {\n  if (enumValues.includes(value) || value === '') {\n    return value;\n  }\n\n  if (value === '[no unit]' || typeof value !== 'string') {\n    return unitNames.find((name) => units[name].unitString === '');\n  }\n\n  const unit = value.replace(/^-?\\d+(\\.\\d+)?/, '');\n\n  return unitNames.find((name) => units[name].unitString === unit) || '';\n}\n\n/**\n * @param {string} unitName A unit name or keyword.\n * @param {string[]} enumValues List of allowed keywords.\n * @returns {boolean} True if unitName indicates that a number is required.\n */\nfunction hasNumber(unitName, enumValues) {\n  return unitName !== '' && !enumValues.includes(unitName);\n}\n</script>\n"
  },
  {
    "path": "ui/components/PropertyInputNumber.vue",
    "content": "<template>\n  <input\n    :required=\"required\"\n    :min=\"min\"\n    :max=\"max\"\n    :data-exclusive-minimum=\"exclusiveMinimum\"\n    :data-exclusive-maximum=\"exclusiveMaximum\"\n    :step=\"step\"\n    :placeholder=\"hint\"\n    :value=\"value === `invalid` ? `` : value\"\n    type=\"number\"\n    v-on=\"lazy ? { change: update } : { input: update }\"\n    @focus=\"$emit('focus', $event)\"\n    @blur=\"$emit('blur', $event)\">\n</template>\n\n<script>\nimport { anyProp, booleanProp, numberProp, objectProp, oneOfTypesProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    schemaProperty: objectProp().required,\n    required: booleanProp().withDefault(false),\n    hint: stringProp().optional,\n    minimum: oneOfTypesProp([Number, String]).optional, // can be the string `invalid`\n    maximum: oneOfTypesProp([Number, String]).optional, // can be the string `invalid`\n    value: anyProp().required,\n    lazy: booleanProp().withDefault(false),\n    stepOverride: numberProp().optional,\n  },\n  emits: {\n    'input': (value) => true,\n    'focus': () => true,\n    'blur': () => true,\n    'vf:validate': (validationData) => true,\n  },\n  computed: {\n    min() {\n      if (this.minimum !== undefined && this.minimum !== 'invalid') {\n        return this.minimum;\n      }\n\n      if ('minimum' in this.schemaProperty) {\n        return this.schemaProperty.minimum;\n      }\n\n      return this.exclusiveMinimum;\n    },\n    max() {\n      if (this.maximum !== undefined && this.maximum !== 'invalid') {\n        return this.maximum;\n      }\n\n      if ('maximum' in this.schemaProperty) {\n        return this.schemaProperty.maximum;\n      }\n\n      return this.exclusiveMaximum;\n    },\n    exclusiveMinimum() {\n      if ('exclusiveMinimum' in this.schemaProperty) {\n        return this.schemaProperty.exclusiveMinimum;\n      }\n\n      return null;\n    },\n    exclusiveMaximum() {\n      if ('exclusiveMaximum' in this.schemaProperty) {\n        return this.schemaProperty.exclusiveMaximum;\n      }\n\n      return null;\n    },\n    step() {\n      if (this.stepOverride !== undefined) {\n        return this.stepOverride;\n      }\n      return this.schemaProperty.type === 'integer' ? 1 : 'any';\n    },\n\n    /**\n     * @public\n     * @returns {Record<string, string | null>} Validation data for vue-form\n     */\n    validationData() {\n      return {\n        'min': this.min === null ? null : `${this.min}`,\n        'max': this.max === null ? null : `${this.max}`,\n        'data-exclusive-minimum': this.exclusiveMinimum === null ? null : `${this.exclusiveMinimum}`,\n        'data-exclusive-maximum': this.exclusiveMaximum === null ? null : `${this.exclusiveMaximum}`,\n        'step': `${this.step}`,\n        'type': 'number',\n      };\n    },\n  },\n  watch: {\n    validationData: {\n      handler(newValidationData) {\n        this.$emit('vf:validate', newValidationData);\n      },\n      deep: true,\n      immediate: true,\n    },\n  },\n  methods: {\n    /** @public */\n    focus() {\n      this.$el.focus();\n    },\n    update() {\n      const input = this.$el;\n      if (input.validity && input.validity.badInput) {\n        this.$emit('input', 'invalid');\n        return;\n      }\n\n      if (input.value === '') {\n        this.$emit('input', null);\n        return;\n      }\n\n      let value;\n      try {\n        value = Number.parseFloat(input.value);\n      }\n      catch {\n        value = 'invalid';\n      }\n\n      this.$emit('input', value);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/PropertyInputRange.vue",
    "content": "<template>\n  <span class=\"range\">\n    <Validate :state=\"formstate\" tag=\"span\">\n      <PropertyInputNumber\n        ref=\"firstInput\"\n        v-model=\"start\"\n        :name=\"`${name}-start`\"\n        :schema-property=\"schemaProperty.items\"\n        :minimum=\"rangeMin\"\n        :maximum=\"end === `invalid` ? rangeMax : end\"\n        :required=\"required || rangeIncomplete\"\n        :hint=\"startHint\"\n        lazy\n        @focus=\"onFocus($event)\"\n        @blur=\"onBlur($event)\" />\n    </Validate>\n    …\n    <Validate :state=\"formstate\" tag=\"span\">\n      <PropertyInputNumber\n        v-model=\"end\"\n        :name=\"`${name}-end`\"\n        :schema-property=\"schemaProperty.items\"\n        :minimum=\"start === `invalid` ? rangeMin : start\"\n        :maximum=\"rangeMax\"\n        :required=\"required || rangeIncomplete\"\n        :hint=\"endHint\"\n        lazy\n        @focus=\"onFocus($event)\"\n        @blur=\"onBlur($event)\" />\n    </Validate>\n    {{ unit }}\n  </span>\n</template>\n\n<script>\nimport { arrayProp, booleanProp, numberProp, objectProp, stringProp } from 'vue-ts-types';\nimport PropertyInputNumber from './PropertyInputNumber.vue';\n\nexport default {\n  components: {\n    PropertyInputNumber,\n  },\n  model: {\n    prop: 'model-value',\n    event: 'update:model-value',\n  },\n  props: {\n    modelValue: arrayProp().withDefault(null),\n    name: stringProp().required,\n    startHint: stringProp().withDefault('start'),\n    endHint: stringProp().withDefault('end'),\n    rangeMin: numberProp().optional,\n    rangeMax: numberProp().optional,\n    schemaProperty: objectProp().required,\n    unit: stringProp().optional,\n    required: booleanProp().withDefault(false),\n    formstate: objectProp().required,\n  },\n  emits: {\n    'update:model-value': (range) => true,\n    'start-updated': () => true,\n    'end-updated': () => true,\n    'focus': () => true,\n    'blur': () => true,\n    'vf:validate': (validationData) => true,\n  },\n  data() {\n    return {\n      validationData: {\n        'complete-range': '',\n        'valid-range': '',\n      },\n    };\n  },\n  computed: {\n    start: {\n      get() {\n        return this.modelValue ? this.modelValue[0] : null;\n      },\n      set(startInput) {\n        this.$emit('update:model-value', getRange(startInput, this.end));\n        this.$emit('start-updated');\n      },\n    },\n    end: {\n      get() {\n        return this.modelValue ? this.modelValue[1] : null;\n      },\n      set(endInput) {\n        this.$emit('update:model-value', getRange(this.start, endInput));\n        this.$emit('end-updated');\n      },\n    },\n    rangeIncomplete() {\n      return this.modelValue && (this.start === null || this.end === null);\n    },\n  },\n  mounted() {\n    this.$emit('vf:validate', this.validationData);\n  },\n  methods: {\n    /** @public */\n    focus() {\n      this.$refs.firstInput.focus();\n    },\n    onFocus(event) {\n      this.$emit('focus');\n    },\n    onBlur(event) {\n      if (!(event.target && event.relatedTarget) || event.target.closest('.range') !== event.relatedTarget.closest('.range')) {\n        this.$emit('blur');\n      }\n    },\n  },\n};\n\n/**\n * @param {number | null} start Start value of the range or null.\n * @param {number | null} end End value of the range or null.\n * @returns {[number, number] | null} Range array with the inputs or null if both inputs were null.\n */\nfunction getRange(start, end) {\n  if (start === null && end === null) {\n    return null;\n  }\n\n  return [start, end];\n}\n</script>\n"
  },
  {
    "path": "ui/components/PropertyInputSelect.vue",
    "content": "<template>\n  <select\n    v-model=\"localValue\"\n    :required=\"required\"\n    :class=\"{ empty: value === `` }\">\n    <option :disabled=\"required\" value=\"\">unknown</option>\n    <option\n      v-for=\"item of schemaProperty.enum\"\n      :key=\"item\"\n      :value=\"item\">{{ item }}</option>\n    <option\n      v-if=\"additionHint\"\n      value=\"[add-value]\">{{ additionHint }}</option>\n  </select>\n</template>\n\n<script>\nimport { anyProp, booleanProp, objectProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    schemaProperty: objectProp().required,\n    required: booleanProp().withDefault(false),\n    additionHint: stringProp().optional,\n    value: anyProp().required,\n  },\n  emits: {\n    input: (value) => true,\n  },\n  computed: {\n    localValue: {\n      get() {\n        return this.value;\n      },\n      set(newValue) {\n        this.$emit('input', newValue);\n      },\n    },\n  },\n  methods: {\n    /** @public */\n    focus() {\n      this.$el.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/PropertyInputText.vue",
    "content": "<template>\n  <input\n    v-model.trim=\"localValue\"\n    :required=\"required\"\n    :placeholder=\"hint\"\n    :pattern=\"schemaProperty.pattern\"\n    :minlength=\"schemaProperty.minLength\"\n    :maxlength=\"schemaProperty.maxLength\"\n    type=\"text\"\n    @input=\"update()\"\n    @blur=\"onBlur()\">\n</template>\n\n<script>\nimport { anyProp, booleanProp, objectProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    schemaProperty: objectProp().required,\n    required: booleanProp().withDefault(false),\n    hint: stringProp().optional,\n    value: anyProp().required,\n  },\n  emits: {\n    'input': (value) => true,\n    'blur': (value) => true,\n    'vf:validate': (validationData) => true,\n  },\n  data() {\n    return {\n      localValue: '',\n    };\n  },\n  computed: {\n    /**\n     * @public\n     * @returns {Record<string, string | null>} Validation data for vue-form\n     */\n    validationData() {\n      return {\n        pattern: 'pattern' in this.schemaProperty ? `${this.schemaProperty.pattern}` : null,\n        minlength: 'minLength' in this.schemaProperty ? `${this.schemaProperty.minLength}` : null,\n        maxlength: 'maxLength' in this.schemaProperty ? `${this.schemaProperty.maxLength}` : null,\n      };\n    },\n  },\n  watch: {\n    value: {\n      handler(newValue) {\n        this.localValue = newValue ? String(newValue) : '';\n      },\n      immediate: true,\n    },\n    validationData: {\n      handler(newValidationData) {\n        this.$emit('vf:validate', newValidationData);\n      },\n      deep: true,\n      immediate: true,\n    },\n  },\n  methods: {\n    /** @public */\n    focus() {\n      this.$el.focus();\n    },\n    update() {\n      this.$emit('input', this.localValue);\n    },\n    async onBlur() {\n      await this.$nextTick();\n      this.$emit('blur', this.localValue);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/PropertyInputTextarea.vue",
    "content": "<template>\n  <textarea\n    v-model.trim=\"localValue\"\n    :required=\"required\"\n    :placeholder=\"hint\"\n    :minlength=\"schemaProperty.minLength\"\n    :maxlength=\"schemaProperty.maxLength\"\n    @input=\"update()\" />\n</template>\n\n<script>\nimport { anyProp, booleanProp, objectProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    schemaProperty: objectProp().required,\n    required: booleanProp().withDefault(false),\n    hint: stringProp().optional,\n    value: anyProp().required,\n  },\n  emits: {\n    'input': (value) => true,\n    'vf:validate': (validationData) => true,\n  },\n  data() {\n    return {\n      localValue: '',\n    };\n  },\n  computed: {\n    /**\n     * @public\n     * @returns {Record<string, string | null>} Validation data for vue-form\n     */\n    validationData() {\n      return {\n        minlength: 'minLength' in this.schemaProperty ? `${this.schemaProperty.minLength}` : null,\n        maxlength: 'maxLength' in this.schemaProperty ? `${this.schemaProperty.maxLength}` : null,\n      };\n    },\n  },\n  watch: {\n    value: {\n      handler(newValue) {\n        this.localValue = newValue ? String(newValue) : '';\n      },\n      immediate: true,\n    },\n    validationData: {\n      handler(newValidationData) {\n        this.$emit('vf:validate', newValidationData);\n      },\n      deep: true,\n      immediate: true,\n    },\n  },\n  methods: {\n    /** @public */\n    focus() {\n      this.$el.focus();\n    },\n    update() {\n      this.$emit('input', this.localValue);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/ThemeSwitcher.vue",
    "content": "<template>\n  <button\n    v-if=\"cssVariablesSupported\"\n    type=\"button\"\n    :title=\"`Switch to ${otherTheme} theme`\"\n    @click.prevent=\"toggleTheme()\">\n    <OflSvg name=\"theme-light-dark\" />\n  </button>\n</template>\n\n<script>\nconst storageKey = 'theme';\n\nlet cookieName = 'theme';\nconst cookieOptions = {\n  path: '/',\n  maxAge: 60 * 60 * 24 * 7 * 4, // 4 weeks\n  sameSite: true,\n};\n\nif (process.env.NODE_ENV === 'production') {\n  cookieName = '__Host-theme';\n  cookieOptions.secure = true;\n}\n\nexport default {\n  data() {\n    return {\n      cssVariablesSupported: false,\n      theme: 'light',\n      prefersDarkMediaQuery: null,\n    };\n  },\n  head() {\n    return {\n      htmlAttrs: {\n        'data-theme': this.theme,\n      },\n      meta: [\n        {\n          hid: 'theme-color',\n          name: 'theme-color',\n          content: this.theme === 'dark' ? '#383838' : '#fafafa', // SCSS: theme-color(header-background)\n        },\n      ],\n    };\n  },\n  computed: {\n    otherTheme() {\n      return this.theme === 'light' ? 'dark' : 'light';\n    },\n  },\n  watch: {\n    theme: {\n      handler(theme) {\n        // set cookie for server-side rendering\n        this.$cookies.set(cookieName, theme, cookieOptions);\n      },\n      immediate: true,\n    },\n  },\n  mounted() {\n    this.cssVariablesSupported = window.CSS && CSS.supports('color', 'var(--primary)');\n\n    if (!this.cssVariablesSupported) {\n      return;\n    }\n\n    window.addEventListener('storage', this.onStorageChange);\n\n    this.prefersDarkMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n    this.prefersDarkMediaQuery.addListener(this.onMediaQueryMatchChange);\n\n    this.onMediaQueryMatchChange();\n  },\n  beforeDestroy() {\n    window.removeEventListener('storage', this.onStorageChange);\n\n    if (this.prefersDarkMediaQuery) {\n      this.prefersDarkMediaQuery.removeListener(this.onMediaQueryMatchChange);\n    }\n  },\n  methods: {\n    getDefaultPreferredTheme() {\n      return this.prefersDarkMediaQuery.matches ? 'dark' : 'light';\n    },\n    onMediaQueryMatchChange() {\n      const savedTheme = localStorage.getItem(storageKey);\n      this.theme = savedTheme || this.getDefaultPreferredTheme();\n    },\n    onStorageChange({ key, newValue }) {\n      if (key === storageKey) {\n        // theme changed in another browser tab\n        this.theme = newValue || this.getDefaultPreferredTheme();\n      }\n    },\n    toggleTheme() {\n      this.theme = this.otherTheme;\n\n      if (this.theme === this.getDefaultPreferredTheme()) {\n        localStorage.removeItem(storageKey);\n      }\n      else {\n        localStorage.setItem(storageKey, this.theme);\n      }\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorCapability.vue",
    "content": "<template>\n  <ConditionalDetails :open=\"capability.open\" class=\"capability\">\n    <template #summary>\n      DMX range\n      <code :class=\"{ unset: start === null }\">{{ start === null ? min : start }}</code> …\n      <code :class=\"{ unset: end === null }\">{{ end === null ? max : end }}</code>:\n      <span :class=\"{ unset: capability.type === `` }\">{{ capability.type || 'Unset' }}</span>\n    </template>\n\n    <div class=\"capability-content\">\n\n      <LabeledInput\n        :formstate=\"formstate\"\n        multiple-inputs\n        :name=\"`capability${capability.uuid}-dmxRange`\"\n        label=\"DMX range\">\n\n        <PropertyInputRange\n          ref=\"firstInput\"\n          v-model=\"capability.dmxRange\"\n          :formstate=\"formstate\"\n          :name=\"`capability${capability.uuid}-dmxRange`\"\n          :schema-property=\"capabilityDmxRange\"\n          :range-min=\"min\"\n          :range-max=\"max\"\n          :start-hint=\"capabilities.length === 1 ? `${min}` : `start`\"\n          :end-hint=\"capabilities.length === 1 ? `${max}` : `end`\"\n          :required=\"capabilities.length > 1\"\n          @start-updated=\"onStartUpdated()\"\n          @end-updated=\"onEndUpdated()\" />\n\n      </LabeledInput>\n\n      <button\n        v-if=\"isChanged\"\n        type=\"button\"\n        class=\"close icon-button\"\n        title=\"Remove capability\"\n        @click.prevent=\"clear()\">\n        <OflSvg name=\"close\" />\n      </button>\n\n      <EditorCapabilityTypeData\n        ref=\"capabilityTypeData\"\n        :capability=\"capability\"\n        :channel=\"channel\"\n        :formstate=\"formstate\"\n        required />\n\n    </div>\n  </ConditionalDetails>\n</template>\n\n<style lang=\"scss\" scoped>\n.capability {\n  position: relative;\n  margin: 0 -0.5rem;\n\n  &:not(:last-child) {\n    border-bottom: 1px solid theme-color(divider);\n  }\n\n  &[open] {\n    padding-bottom: 1.5rem;\n    margin-bottom: 0.8rem;\n  }\n\n  & ::v-deep summary {\n    padding: 0.3rem 0.5rem;\n  }\n}\n\n.capability-content {\n  padding: 0 1.5rem;\n}\n\n.unset {\n  color: theme-color(text-disabled);\n}\n\n.icon-button.close {\n  position: absolute;\n  top: 0;\n  right: 0;\n}\n</style>\n\n<script>\nimport { numberProp, objectProp } from 'vue-ts-types';\nimport { capabilityDmxRange } from '../../../lib/schema-properties.js';\nimport { getEmptyCapability, isCapabilityChanged } from '../../assets/scripts/editor-utilities.js';\nimport ConditionalDetails from '../ConditionalDetails.vue';\nimport LabeledInput from '../LabeledInput.vue';\nimport PropertyInputRange from '../PropertyInputRange.vue';\nimport EditorCapabilityTypeData from './EditorCapabilityTypeData.vue';\n\nexport default {\n  components: {\n    ConditionalDetails,\n    EditorCapabilityTypeData,\n    LabeledInput,\n    PropertyInputRange,\n  },\n  props: {\n    channel: objectProp().required,\n    capabilityIndex: numberProp().required,\n    resolution: numberProp().required,\n    formstate: objectProp().required,\n  },\n  emits: {\n    'insert-capability-before': () => true,\n    'insert-capability-after': () => true,\n  },\n  data() {\n    return {\n      dmxMin: 0,\n      capabilityDmxRange,\n    };\n  },\n  computed: {\n    capabilities() {\n      return this.channel.capabilities;\n    },\n    capability() {\n      return this.capabilities[this.capabilityIndex];\n    },\n    dmxMax() {\n      return Math.pow(256, this.resolution) - 1;\n    },\n    isChanged() {\n      return this.capabilities.some(\n        (capability) => isCapabilityChanged(capability),\n      );\n    },\n    start() {\n      return this.capability.dmxRange === null ? null : this.capability.dmxRange[0];\n    },\n    end() {\n      return this.capability.dmxRange === null ? null : this.capability.dmxRange[1];\n    },\n    min() {\n      let min = this.dmxMin;\n      let index = this.capabilityIndex - 1;\n      while (index >= 0) {\n        const capability = this.capabilities[index];\n        if (capability.dmxRange !== null) {\n          if (capability.dmxRange[1]) {\n            min = capability.dmxRange[1] + 1;\n            break;\n          }\n          if (capability.dmxRange[0] !== null) {\n            min = capability.dmxRange[0] + 1;\n            break;\n          }\n        }\n        index--;\n      }\n      return min;\n    },\n    max() {\n      let max = this.dmxMax;\n      let index = this.capabilityIndex + 1;\n      while (index < this.capabilities.length) {\n        const capability = this.capabilities[index];\n        if (capability.dmxRange !== null) {\n          if (capability.dmxRange[0] !== null) {\n            max = capability.dmxRange[0] - 1;\n            break;\n          }\n          if (capability.dmxRange[1] !== null) {\n            max = capability.dmxRange[1] - 1;\n            break;\n          }\n        }\n        index++;\n      }\n      return max;\n    },\n  },\n  methods: {\n    onStartUpdated() {\n      if (this.start === null) {\n        const previousCapability = this.capabilities[this.capabilityIndex - 1];\n        if (previousCapability && !isCapabilityChanged(previousCapability)) {\n          this.removePreviousCapability();\n        }\n        return;\n      }\n\n      const previousCapability = this.capabilities[this.capabilityIndex - 1];\n      if (previousCapability) {\n        if (isCapabilityChanged(previousCapability)) {\n          if (this.start > this.min) {\n            this.insertCapabilityBefore();\n          }\n          return;\n        }\n\n        if (this.start <= this.min) {\n          this.removePreviousCapability();\n        }\n        return;\n      }\n\n      if (this.start > this.dmxMin) {\n        this.insertCapabilityBefore();\n      }\n    },\n    onEndUpdated() {\n      if (this.end === null) {\n        const nextCapability = this.capabilities[this.capabilityIndex + 1];\n        if (nextCapability && !isCapabilityChanged(nextCapability)) {\n          this.removeNextCapability();\n        }\n        return;\n      }\n\n      const nextCapability = this.capabilities[this.capabilityIndex + 1];\n      if (nextCapability) {\n        if (isCapabilityChanged(nextCapability)) {\n          if (this.end < this.max) {\n            this.insertCapabilityAfter();\n          }\n          return;\n        }\n\n        if (this.end >= this.max) {\n          this.removeNextCapability();\n        }\n        return;\n      }\n\n      if (this.end < this.dmxMax) {\n        this.insertCapabilityAfter();\n      }\n    },\n    clear() {\n      const emptyCapability = getEmptyCapability();\n      for (const property of Object.keys(emptyCapability)) {\n        this.capability[property] = emptyCapability[property];\n      }\n      this.collapseWithNeighbors();\n    },\n    collapseWithNeighbors() {\n      const previousCapability = this.capabilities[this.capabilityIndex - 1];\n      const nextCapability = this.capabilities[this.capabilityIndex + 1];\n\n      if (previousCapability && !isCapabilityChanged(previousCapability)) {\n        if (nextCapability && !isCapabilityChanged(nextCapability)) {\n          this.removePreviousCapability();\n          this.removeCurrentCapability();\n          return;\n        }\n\n        this.removePreviousCapability();\n        return;\n      }\n\n      if (nextCapability && !isCapabilityChanged(nextCapability)) {\n        this.removeNextCapability();\n      }\n    },\n    async insertCapabilityBefore() {\n      this.$emit('insert-capability-before');\n\n      const dialog = this.$el.closest('.dialog');\n      await this.$nextTick();\n\n      const newCapability = dialog.querySelector('.capability-editor').children[this.capabilityIndex - 1];\n      dialog.scrollTop += newCapability.clientHeight;\n    },\n    insertCapabilityAfter() {\n      this.$emit('insert-capability-after');\n    },\n    removePreviousCapability() {\n      this.$delete(this.capabilities, this.capabilityIndex - 1);\n    },\n    removeCurrentCapability() {\n      this.$delete(this.capabilities, this.capabilityIndex);\n    },\n    removeNextCapability() {\n      this.$delete(this.capabilities, this.capabilityIndex + 1);\n    },\n\n    /** @public */\n    cleanCapabilityData() {\n      if (this.capability.dmxRange === null) {\n        this.capability.dmxRange = [null, null];\n      }\n      if (this.capability.dmxRange[0] === null) {\n        this.capability.dmxRange[0] = this.min;\n      }\n      if (this.capability.dmxRange[1] === null) {\n        this.capability.dmxRange[1] = this.max;\n      }\n\n      this.$refs.capabilityTypeData.cleanCapabilityData();\n    },\n\n    /** @public */\n    focus() {\n      this.$refs.firstInput.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorCapabilityTypeData.vue",
    "content": "<template>\n  <div class=\"editor-capability-type-data\">\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-type`\"\n      :hint=\"capabilityTypeHint\"\n      label=\"Capability type\">\n      <select\n        v-model=\"capability.type\"\n        :class=\"{ empty: capability.type === `` }\"\n        :name=\"`capability${capability.uuid}-type`\"\n        :required=\"required\">\n\n        <option value=\"\" disabled>Please select a capability type</option>\n\n        <option\n          v-for=\"type of capabilityTypes\"\n          :key=\"type\"\n          :value=\"type\">{{ type }}</option>\n\n      </select>\n    </LabeledInput>\n\n    <Component\n      :is=\"`Capability${capability.type}`\"\n      v-if=\"capability.type !== ``\"\n      ref=\"capabilityTypeData\"\n      :capability=\"capability\"\n      :channel=\"channel\"\n      :formstate=\"formstate\" />\n  </div>\n</template>\n\n<script>\nimport { booleanProp, objectProp } from 'vue-ts-types';\nimport { capabilityTypes } from '../../../lib/schema-properties.js';\nimport LabeledInput from '../LabeledInput.vue';\nimport CapabilityBeamAngle from './capabilities/CapabilityBeamAngle.vue';\nimport CapabilityBeamPosition from './capabilities/CapabilityBeamPosition.vue';\nimport CapabilityBladeInsertion from './capabilities/CapabilityBladeInsertion.vue';\nimport CapabilityBladeRotation from './capabilities/CapabilityBladeRotation.vue';\nimport CapabilityBladeSystemRotation from './capabilities/CapabilityBladeSystemRotation.vue';\nimport CapabilityColorIntensity from './capabilities/CapabilityColorIntensity.vue';\nimport CapabilityColorPreset from './capabilities/CapabilityColorPreset.vue';\nimport CapabilityColorTemperature from './capabilities/CapabilityColorTemperature.vue';\nimport CapabilityEffect from './capabilities/CapabilityEffect.vue';\nimport CapabilityEffectDuration from './capabilities/CapabilityEffectDuration.vue';\nimport CapabilityEffectParameter from './capabilities/CapabilityEffectParameter.vue';\nimport CapabilityEffectSpeed from './capabilities/CapabilityEffectSpeed.vue';\nimport CapabilityFocus from './capabilities/CapabilityFocus.vue';\nimport CapabilityFog from './capabilities/CapabilityFog.vue';\nimport CapabilityFogOutput from './capabilities/CapabilityFogOutput.vue';\nimport CapabilityFogType from './capabilities/CapabilityFogType.vue';\nimport CapabilityFrost from './capabilities/CapabilityFrost.vue';\nimport CapabilityFrostEffect from './capabilities/CapabilityFrostEffect.vue';\nimport CapabilityGeneric from './capabilities/CapabilityGeneric.vue';\nimport CapabilityIntensity from './capabilities/CapabilityIntensity.vue';\nimport CapabilityIris from './capabilities/CapabilityIris.vue';\nimport CapabilityIrisEffect from './capabilities/CapabilityIrisEffect.vue';\nimport CapabilityMaintenance from './capabilities/CapabilityMaintenance.vue';\nimport CapabilityNoFunction from './capabilities/CapabilityNoFunction.vue';\nimport CapabilityPan from './capabilities/CapabilityPan.vue';\nimport CapabilityPanContinuous from './capabilities/CapabilityPanContinuous.vue';\nimport CapabilityPanTiltSpeed from './capabilities/CapabilityPanTiltSpeed.vue';\nimport CapabilityPrism from './capabilities/CapabilityPrism.vue';\nimport CapabilityPrismRotation from './capabilities/CapabilityPrismRotation.vue';\nimport CapabilityRotation from './capabilities/CapabilityRotation.vue';\nimport CapabilityShutterStrobe from './capabilities/CapabilityShutterStrobe.vue';\nimport CapabilitySoundSensitivity from './capabilities/CapabilitySoundSensitivity.vue';\nimport CapabilitySpeed from './capabilities/CapabilitySpeed.vue';\nimport CapabilityStrobeDuration from './capabilities/CapabilityStrobeDuration.vue';\nimport CapabilityStrobeSpeed from './capabilities/CapabilityStrobeSpeed.vue';\nimport CapabilityTilt from './capabilities/CapabilityTilt.vue';\nimport CapabilityTiltContinuous from './capabilities/CapabilityTiltContinuous.vue';\nimport CapabilityTime from './capabilities/CapabilityTime.vue';\nimport CapabilityWheelRotation from './capabilities/CapabilityWheelRotation.vue';\nimport CapabilityWheelShake from './capabilities/CapabilityWheelShake.vue';\nimport CapabilityWheelSlot from './capabilities/CapabilityWheelSlot.vue';\nimport CapabilityWheelSlotRotation from './capabilities/CapabilityWheelSlotRotation.vue';\nimport CapabilityZoom from './capabilities/CapabilityZoom.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    CapabilityNoFunction,\n    CapabilityShutterStrobe,\n    CapabilityStrobeSpeed,\n    CapabilityStrobeDuration,\n    CapabilityIntensity,\n    CapabilityColorIntensity,\n    CapabilityColorPreset,\n    CapabilityColorTemperature,\n    CapabilityPan,\n    CapabilityPanContinuous,\n    CapabilityTilt,\n    CapabilityTiltContinuous,\n    CapabilityPanTiltSpeed,\n    CapabilityWheelSlot,\n    CapabilityWheelShake,\n    CapabilityWheelSlotRotation,\n    CapabilityWheelRotation,\n    CapabilityEffect,\n    CapabilityEffectSpeed,\n    CapabilityEffectDuration,\n    CapabilityEffectParameter,\n    CapabilitySoundSensitivity,\n    CapabilityBeamAngle,\n    CapabilityBeamPosition,\n    CapabilityFocus,\n    CapabilityZoom,\n    CapabilityIris,\n    CapabilityIrisEffect,\n    CapabilityFrost,\n    CapabilityFrostEffect,\n    CapabilityPrism,\n    CapabilityPrismRotation,\n    CapabilityBladeInsertion,\n    CapabilityBladeRotation,\n    CapabilityBladeSystemRotation,\n    CapabilityFog,\n    CapabilityFogOutput,\n    CapabilityFogType,\n    CapabilityRotation,\n    CapabilitySpeed,\n    CapabilityTime,\n    CapabilityMaintenance,\n    CapabilityGeneric,\n  },\n  props: {\n    capability: objectProp().required,\n    channel: objectProp().required,\n    formstate: objectProp().optional,\n    required: booleanProp().withDefault(false),\n  },\n  data() {\n    return {\n      capabilityTypes: Object.keys(capabilityTypes),\n      capabilityTypeHint: null,\n    };\n  },\n  watch: {\n    async 'capability.type'() {\n      // Add all properties to capability.typeData that are required by the current capability type and are not yet in there.\n\n      await this.$nextTick();\n\n      const defaultData = this.$refs.capabilityTypeData.defaultData;\n      for (const property of Object.keys(defaultData)) {\n        if (!(property in this.capability.typeData)) {\n          this.$set(this.capability.typeData, property, defaultData[property]);\n        }\n      }\n\n      this.capabilityTypeHint = 'hint' in this.$refs.capabilityTypeData\n        ? this.$refs.capabilityTypeData.hint\n        : null;\n    },\n  },\n  methods: {\n    /**\n     * Called when the channel is saved. Removes all properties from capability.typeData that are not relevant for this capability type and sets open to false.\n     * @public\n     */\n    cleanCapabilityData() {\n      const component = this.$refs.capabilityTypeData;\n\n      const defaultData = component.defaultData;\n\n      for (const property of Object.keys(this.capability.typeData)) {\n        if (!(property in defaultData)) {\n          delete this.capability.typeData[property];\n        }\n      }\n\n      if (component && 'resetProperties' in component) {\n        const resetProperties = component.resetProperties;\n\n        for (const property of resetProperties) {\n          const defaultPropertyData = defaultData[property];\n          this.capability.typeData[property] = typeof defaultPropertyData === 'string' ? '' : defaultPropertyData;\n        }\n      }\n\n      this.capability.open = false;\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorCapabilityWizard.vue",
    "content": "<template>\n  <div class=\"capability-wizard\">\n\n    <span>Generate multiple capabilities with same range width. Occurrences of '#' in text fields will be replaced by an increasing number.</span>\n\n    <section>\n      <label>\n        <LabeledValue label=\"DMX start value\">\n          <input\n            ref=\"firstInput\"\n            v-model.number=\"wizard.start\"\n            :max=\"dmxMax\"\n            type=\"number\"\n            min=\"0\"\n            step=\"1\">\n        </LabeledValue>\n      </label>\n    </section>\n\n    <section>\n      <label>\n        <LabeledValue label=\"Range width\">\n          <input\n            v-model.number=\"wizard.width\"\n            :max=\"dmxMax\"\n            type=\"number\"\n            min=\"1\"\n            step=\"1\">\n        </LabeledValue>\n      </label>\n    </section>\n\n    <section>\n      <label>\n        <LabeledValue label=\"Count\">\n          <input\n            v-model.number=\"wizard.count\"\n            :max=\"dmxMax\"\n            type=\"number\"\n            min=\"1\"\n            step=\"1\">\n        </LabeledValue>\n      </label>\n    </section>\n\n    <EditorCapabilityTypeData\n      :capability=\"wizard.templateCapability\"\n      :channel=\"channel\" />\n\n    <table class=\"capabilities-table\">\n      <colgroup>\n        <col style=\"width: 5.8ex;\">\n        <col style=\"width: 1ex;\">\n        <col style=\"width: 5.8ex;\">\n        <col>\n      </colgroup>\n      <thead><tr>\n        <th colspan=\"3\" style=\"text-align: center;\">DMX values</th>\n        <th>Capability</th>\n      </tr></thead>\n      <tbody>\n        <tr v-for=\"capability of allCapabilities\" :key=\"capability.uuid\" :class=\"capability.source\">\n          <td class=\"capability-dmx-range-start\"><code>{{ capability.dmxRange[0] }}</code></td>\n          <td class=\"capability-dmx-range-separator\"><code>…</code></td>\n          <td class=\"capability-dmx-range-end\"><code>{{ capability.dmxRange[1] }}</code></td>\n          <td class=\"capability-type\">{{ capability.type }}</td>\n        </tr>\n      </tbody>\n    </table>\n\n    <span v-if=\"error\" class=\"error-message\">{{ error }}</span>\n\n    <div class=\"button-bar right\">\n      <button\n        type=\"button\"\n        :disabled=\"error || !wizard.templateCapability.type\"\n        class=\"restore primary\"\n        @click.prevent=\"apply()\">\n        Generate capabilities\n      </button>\n    </div>\n\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n// TODO: a lot of this stuff is duplicated in FixturePageCapabilityTable.vue\n\n.capabilities-table {\n  margin-top: 1em;\n  table-layout: fixed;\n  border-collapse: collapse;\n}\n\nth {\n  font-weight: 400;\n  color: theme-color(text-secondary);\n}\n\ntd,\nth {\n  padding: 0 4px;\n  vertical-align: top;\n}\n\n.capability-dmx-range-start {\n  padding-right: 2px;\n  text-align: right;\n}\n\n.capability-dmx-range-separator {\n  padding-right: 0;\n  padding-left: 0;\n  text-align: center;\n}\n\n.capability-dmx-range-end {\n  padding-left: 2px;\n  text-align: left;\n}\n\n.inherited,\n.inherited code {\n  color: theme-color(text-disabled);\n}\n\n.computed,\n.computed code {\n  color: theme-color(text-primary);\n}\n</style>\n\n<script>\nimport { numberProp, objectProp } from 'vue-ts-types';\nimport {\n  getEmptyCapability,\n  isCapabilityChanged,\n} from '../../assets/scripts/editor-utilities.js';\nimport LabeledValue from '../LabeledValue.vue';\nimport EditorCapabilityTypeData from './EditorCapabilityTypeData.vue';\n\n/**\n * @param {object} capabilityTypeData The generated capability's type data.\n * @param {number} index The index of the generated capability.\n */\nfunction replaceHashWithIndex(capabilityTypeData, index) {\n  if ('effectName' in capabilityTypeData) {\n    capabilityTypeData.effectName = capabilityTypeData.effectName.replace(/#/, index + 1);\n  }\n  if ('comment' in capabilityTypeData) {\n    capabilityTypeData.comment = capabilityTypeData.comment.replace(/#/, index + 1);\n  }\n}\n\nexport default {\n  components: {\n    LabeledValue,\n    EditorCapabilityTypeData,\n  },\n  props: {\n    channel: objectProp().required,\n    resolution: numberProp().required,\n    wizard: objectProp().required,\n  },\n  emits: {\n    close: (insertIndex) => true,\n  },\n  computed: {\n    capabilities() {\n      return this.channel.capabilities;\n    },\n\n    /**\n     * @returns {number} Maximum allowed DMX value.\n     */\n    dmxMax() {\n      return Math.pow(256, this.resolution) - 1;\n    },\n\n    /**\n     * @returns {number} Index in capabilities array where the generated capabilities need to be inserted.\n     */\n    insertIndex() {\n      // loop from inherited capabilities array end to start\n      for (let index = this.capabilities.length - 1; index >= 0; index--) {\n        if (this.capabilities[index].dmxRange !== null && this.capabilities[index].dmxRange[1] !== null && this.capabilities[index].dmxRange[1] < this.wizard.start) {\n          return index + 1;\n        }\n      }\n\n      return 0;\n    },\n\n    /**\n     * @returns {object[]} Generated capabilities. An empty capability is prepended to fill the gap if neccessary.\n     */\n    computedCapabilites() {\n      const capabilities = [];\n\n      const previousCapability = this.capabilities[this.insertIndex - 1];\n      if (\n        (!previousCapability && this.wizard.start > 0)\n        || (previousCapability && previousCapability.dmxRange !== null && this.wizard.start > previousCapability.dmxRange[1] + 1)\n      ) {\n        // empty capability filling the gap before generated capabilities\n        capabilities.push(getEmptyCapability());\n      }\n\n      for (let index = 0; index < this.wizard.count; index++) {\n        const capability = getEmptyCapability();\n\n        capability.dmxRange = [\n          this.wizard.start + (index * this.wizard.width),\n          this.wizard.start + ((index + 1) * this.wizard.width) - 1,\n        ];\n        capability.type = this.wizard.templateCapability.type;\n        capability.typeData = structuredClone(this.wizard.templateCapability.typeData);\n        replaceHashWithIndex(capability.typeData, index);\n\n        capabilities.push(capability);\n      }\n\n      return capabilities;\n    },\n\n    /**\n     * @returns {number} Number of (empty) capabilities to remove after the generated ones.\n     */\n    removeCount() {\n      const nextCapability = this.capabilities[this.insertIndex];\n      if (nextCapability && isCapabilityChanged(nextCapability)) {\n        // non-empty capability (should not occur here, but should not be removed anyway)\n        return 0;\n      }\n\n      if (this.end === this.dmxMax) {\n        return 1;\n      }\n\n      const nextNonEmptyCapability = this.capabilities[this.insertIndex + 1];\n      if (nextNonEmptyCapability && nextNonEmptyCapability.dmxRange !== null && this.end + 1 === nextNonEmptyCapability.dmxRange[0]) {\n        return 1;\n      }\n\n      return 0;\n    },\n\n    /**\n     * @returns {number} DMX value range end of the last generated capability.\n     */\n    end() {\n      return this.computedCapabilites.length === 0 ? -1 : this.computedCapabilites.at(-1).dmxRange[1];\n    },\n\n    /**\n     * @see {@link getCapabilityWithSource}\n     * @returns {object[]} Array of all capabilities (generated and inherited), combined with their source.\n     */\n    allCapabilities() {\n      const inheritedCapabilities = this.capabilities.map(\n        (capability) => getCapabilityWithSource(capability, 'inherited'),\n      );\n\n      const computedCapabilites = this.computedCapabilites.map(\n        (capability) => getCapabilityWithSource(capability, 'computed'),\n      );\n\n      // insert all computed capabilities at insertIndex\n      inheritedCapabilities.splice(this.insertIndex, this.removeCount, ...computedCapabilites);\n\n      return inheritedCapabilities.filter(\n        (capability) => capability.dmxRange !== null,\n      );\n    },\n\n    /**\n     * Performs validation of the user input.\n     * @returns {string | null} A string with an validation error, or null if there is no error.\n     */\n    validationError() {\n      if (this.wizard.start < 0) {\n        return 'Capabilities must not start below DMX value 0.';\n      }\n\n      if (this.wizard.width <= 0) {\n        return 'Capability width must be greater than zero.';\n      }\n\n      if (this.wizard.start % 1 !== 0 || this.wizard.width % 1 !== 0 || this.wizard.count % 1 !== 0) {\n        return 'Please only enter whole numbers.';\n      }\n\n      return null;\n    },\n\n    /**\n     * @returns {string | null} A string with an error that prevents the generated capabilities from being saved, or null if there is no error.\n     */\n    error() {\n      if (this.validationError) {\n        return this.validationError;\n      }\n\n      if (this.end > this.dmxMax) {\n        return `Capabilities must not end above DMX value ${this.dmxMax}.`;\n      }\n\n      const collisionDetected = this.capabilities.some((capability) => {\n        if (capability.dmxRange === null) {\n          return false;\n        }\n\n        // if only start or end is set, assume a one-value dmxRange (e.g. [43, 43])\n        const capabilityStart = capability.dmxRange[0] === null ? capability.dmxRange[1] : capability.dmxRange[0];\n        const capabilityEnd = capability.dmxRange[1] === null ? capability.dmxRange[0] : capability.dmxRange[1];\n\n        return capabilityEnd >= this.wizard.start && capabilityStart <= this.end;\n      });\n      if (collisionDetected) {\n        return 'Generated capabilities must not overlap with existing ones.';\n      }\n\n      return null;\n    },\n  },\n  mounted() {\n    if (this.$root._oflRestoreComplete) {\n      this.$refs.firstInput.focus();\n    }\n\n    let lastOccupied = -1;\n    for (let index = this.capabilities.length - 1; index >= 0; index--) {\n      const capability = this.capabilities[index];\n\n      if (capability.dmxRange === null) {\n        continue;\n      }\n\n      if (capability.dmxRange[1] !== null) {\n        lastOccupied = capability.dmxRange[1];\n        break;\n      }\n\n      if (capability.dmxRange[0] !== null) {\n        lastOccupied = capability.dmxRange[0];\n        break;\n      }\n    }\n\n    this.wizard.start = lastOccupied + 1;\n  },\n  methods: {\n    /**\n     * Applies the generated capabilities into the capabilities prop and emits a \"close\" event.\n     */\n    apply() {\n      if (this.error) {\n        return;\n      }\n\n      // close other capabilities if they are not empty\n      for (const capability of this.capabilities) {\n        if (capability.type !== '') {\n          capability.open = false;\n        }\n      }\n\n      // insert all computed capabilities at insertIndex\n      this.capabilities.splice(this.insertIndex, this.removeCount, ...this.computedCapabilites);\n\n      this.$emit('close', this.insertIndex);\n    },\n  },\n};\n\n/**\n * @param {object} capability The \"full\" capability object.\n * @param {string} source The source of the capability (inherited or computed).\n * @returns {object} A capability object that additionally contains the specified source.\n */\nfunction getCapabilityWithSource(capability, source) {\n  return { ...capability, source };\n}\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorCategoryChooser.vue",
    "content": "<template>\n  <div>\n    <Draggable v-model=\"selectedCategories\" tag=\"span\">\n      <CategoryBadge\n        v-for=\"cat of value\"\n        :key=\"cat\"\n        :category=\"cat\"\n        selected\n        selectable\n        @click=\"deselect(cat)\"\n        @focus=\"onFocus()\"\n        @blur=\"onBlur($event)\" />\n    </Draggable>\n\n    <CategoryBadge\n      v-for=\"cat of unselectedCategories\"\n      :key=\"cat\"\n      :category=\"cat\"\n      selectable\n      @click=\"select(cat)\"\n      @focus=\"onFocus()\"\n      @blur=\"onBlur($event)\" />\n  </div>\n</template>\n\n<script>\nimport { arrayProp } from 'vue-ts-types';\nimport Draggable from 'vuedraggable';\nimport CategoryBadge from '../CategoryBadge.vue';\n\nexport default {\n  components: {\n    Draggable,\n    CategoryBadge,\n  },\n  props: {\n    value: arrayProp().required,\n    allCategories: arrayProp().required,\n  },\n  emits: {\n    input: (value) => true,\n    focus: () => true,\n    blur: () => true,\n  },\n  computed: {\n    selectedCategories: {\n      get() {\n        return this.value;\n      },\n      set(newSelectedCategories) {\n        this.$emit('input', newSelectedCategories);\n      },\n    },\n    unselectedCategories() {\n      return this.allCategories.filter(\n        (category) => !this.value.includes(category),\n      );\n    },\n  },\n  methods: {\n    select(selectedCategory) {\n      const updatedCategoryList = [...this.value, selectedCategory];\n      this.$emit('input', updatedCategoryList);\n      this.onBlur();\n    },\n    deselect(deselectedCategory) {\n      const updatedCategoryList = this.value.filter((category) => category !== deselectedCategory);\n      this.$emit('input', updatedCategoryList);\n      this.onBlur();\n    },\n    onFocus() {\n      this.$emit('focus');\n    },\n    onBlur(event) {\n      if (!(event && event.target && event.relatedTarget) || event.target.parentNode !== event.relatedTarget.parentNode) {\n        this.$emit('blur');\n      }\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorChannelDialog.vue",
    "content": "<template>\n  <A11yDialog\n    id=\"channel-dialog\"\n    ref=\"channelDialog\"\n    :shown=\"channel.editMode !== `` && channel.editMode !== `edit-?`\"\n    :title=\"title\"\n    :class=\"`channel-dialog-${channel.editMode}`\"\n    @show=\"onChannelDialogOpen()\"\n    @hide=\"onChannelDialogClose()\">\n\n    <VueForm\n      :state=\"formstate\"\n      action=\"#\"\n      @submit.prevent=\"onSubmit()\">\n\n      <div v-if=\"channel.editMode === `add-existing`\" class=\"existing-channel-input-container\">\n        <LabeledInput\n          :formstate=\"formstate\"\n          name=\"existingChannelUuid\"\n          multiple-inputs>\n          <input\n            v-model=\"selectedChannelUuidsString\"\n            name=\"existingChannelUuid\"\n            type=\"hidden\"\n            required>\n          <fieldset class=\"channel-list\">\n            <legend>Select existing channel(s)</legend>\n            <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -- double click is just a shortcut, all functionality is still accessible via keyboard -->\n            <label\n              v-for=\"item of currentModeUnchosenChannels\"\n              :key=\"item.uuid\"\n              :for=\"item.inputId\"\n              class=\"channel-list-item\"\n              @dblclick=\"onChannelDoubleClick(item.uuid)\">\n              <input\n                :id=\"item.inputId\"\n                :checked=\"item.isSelected\"\n                type=\"checkbox\"\n                class=\"channel-checkbox\"\n                @change=\"toggleChannelSelection(item.uuid)\">\n              <span class=\"channel-name\">{{ item.name }}</span>\n              <code v-if=\"item.showUuid\" class=\"channel-uuid\">{{ item.uuid }}</code>\n            </label>\n          </fieldset>\n        </LabeledInput>\n\n        <p>or <a href=\"#create-channel\" @click.prevent=\"setEditModeCreate()\">create a new channel</a></p>\n      </div>\n\n      <div v-else>\n        <LabeledInput :formstate=\"formstate\" name=\"name\" label=\"Name\">\n          <PropertyInputText\n            v-model=\"channel.name\"\n            :schema-property=\"channelProperties.name\"\n            required\n            name=\"name\"\n            start-with-uppercase-or-number\n            no-fine-channel-name\n            list=\"channel-name-suggestions\"\n            title=\"Please start with an uppercase letter or a number. Don't create fine channels here, set its resolution below instead.\"\n            class=\"channelName\"\n            @blur=\"onChannelNameChanged($event)\" />\n        </LabeledInput>\n\n        <datalist id=\"channel-name-suggestions\" hidden>\n          <option>Intensity</option>\n          <option>Dimmer</option>\n          <option>Shutter / Strobe</option>\n          <option>Shutter</option>\n          <option>Strobe</option>\n          <option>Strobe Speed</option>\n          <option>Strobe Duration</option>\n          <option v-for=\"color of singleColors\" :key=\"color\">{{ color }}</option>\n          <option>Color Macros</option>\n          <option>Color Presets</option>\n          <option>Color Wheel</option>\n          <option>Color Wheel Rotation</option>\n          <option>Color Temperature</option>\n          <option>CTC</option>\n          <option>CTO</option>\n          <option>CTB</option>\n          <option>Pan</option>\n          <option>Tilt</option>\n          <option>Pan/Tilt Speed</option>\n          <option>Pan/Tilt Duration</option>\n          <option>Effect Speed</option>\n          <option>Program Speed</option>\n          <option>Effect Duration</option>\n          <option>Program Duration</option>\n          <option>Sound Sensitivity</option>\n          <option>Gobo Wheel</option>\n          <option>Gobo Wheel Rotation</option>\n          <option>Gobo Stencil Rotation</option>\n          <option>Focus</option>\n          <option>Zoom</option>\n          <option>Iris</option>\n          <option>Frost</option>\n          <option>Prism</option>\n          <option>Prism Rotation</option>\n          <option>Blade Insertion</option>\n          <option>Blade Rotation</option>\n          <option>Blade System Rotation</option>\n          <option>Fog</option>\n          <option>Haze</option>\n          <option>Fog Output</option>\n          <option>Fog Intensity</option>\n          <option>No function</option>\n          <option>Reserved</option>\n        </datalist>\n\n        <LabeledInput :formstate=\"formstate\" name=\"resolution\" label=\"Channel resolution\">\n          <!-- eslint-disable-next-line vuejs-accessibility/no-onchange -- @change is fine here, as the action is non-destructive -->\n          <select v-model=\"channel.resolution\" name=\"resolution\" @change=\"onResolutionChanged()\">\n            <option :value=\"constants.RESOLUTION_8BIT\">8 bit (No fine channels)</option>\n            <option :value=\"constants.RESOLUTION_16BIT\">16 bit (1 fine channel)</option>\n            <option :value=\"constants.RESOLUTION_24BIT\">24 bit (2 fine channels)</option>\n          </select>\n        </LabeledInput>\n\n        <LabeledInput\n          v-if=\"channel.resolution > constants.RESOLUTION_8BIT\"\n          :formstate=\"formstate\"\n          name=\"dmxValueResolution\"\n          label=\"DMX value resolution\">\n          <!-- eslint-disable-next-line vuejs-accessibility/no-onchange -- @change is fine here, as the action is non-destructive -->\n          <select\n            v-model=\"channel.dmxValueResolution\"\n            name=\"dmxValueResolution\"\n            required\n            @change=\"onDmxValueResolutionChanged()\">\n            <option :value=\"constants.RESOLUTION_8BIT\">8 bit (range 0…255)</option>\n            <option v-if=\"channel.resolution >= constants.RESOLUTION_16BIT\" :value=\"constants.RESOLUTION_16BIT\">16 bit (range 0…65535)</option>\n            <option v-if=\"channel.resolution >= constants.RESOLUTION_24BIT\" :value=\"constants.RESOLUTION_24BIT\">24 bit (range 0…16777215)</option>\n          </select>\n        </LabeledInput>\n\n        <LabeledInput\n          :formstate=\"formstate\"\n          multiple-inputs\n          name=\"defaultValue\"\n          label=\"Default DMX value\">\n          <PropertyInputEntity\n            v-model=\"channel.defaultValue\"\n            :schema-property=\"channelProperties.defaultValue\"\n            :min-number=\"0\"\n            :max-number=\"(typeof channel.defaultValue) === `string` ? 100 : dmxMax\"\n            wide\n            name=\"defaultValue\" />\n        </LabeledInput>\n\n        <h3>Capabilities<template v-if=\"!channel.wizard.show && channel.capabilities.length > 1\">\n          <button\n            type=\"button\"\n            class=\"icon-button expand-all\"\n            title=\"Expand all channels\"\n            @click.prevent=\"openDetails()\">\n            <OflSvg name=\"chevron-double-down\" />\n          </button>\n          <button\n            type=\"button\"\n            class=\"icon-button collapse-all\"\n            title=\"Collapse all channels\"\n            @click.prevent=\"closeDetails()\">\n            <OflSvg name=\"chevron-double-up\" />\n          </button>\n        </template></h3>\n\n        <EditorCapabilityWizard\n          v-if=\"channel.wizard.show\"\n          :wizard=\"channel.wizard\"\n          :channel=\"channel\"\n          :resolution=\"channel.dmxValueResolution\"\n          @close=\"onWizardClose($event)\" />\n\n        <div v-else class=\"capability-editor\">\n          <EditorCapability\n            v-for=\"(cap, index) of channel.capabilities\"\n            ref=\"capabilities\"\n            :key=\"cap.uuid\"\n            :channel=\"channel\"\n            :formstate=\"formstate\"\n            :capability-index=\"index\"\n            :resolution=\"channel.dmxValueResolution\"\n            @insert-capability-before=\"insertEmptyCapability(index)\"\n            @insert-capability-after=\"insertEmptyCapability(index + 1)\" />\n        </div>\n\n        <section>\n          <a href=\"#wizard\" class=\"button secondary\" @click.prevent=\"setWizardVisibility(!channel.wizard.show)\">\n            <OflSvg name=\"capability-wizard\" />\n            {{ channel.wizard.show ? 'Close' : 'Open' }} Capability Wizard\n          </a>\n        </section>\n\n        <h3>Advanced channel settings</h3>\n\n        <LabeledInput\n          :formstate=\"formstate\"\n          multiple-inputs\n          name=\"highlightValue\"\n          label=\"Highlight DMX value\">\n          <PropertyInputEntity\n            v-model=\"channel.highlightValue\"\n            :schema-property=\"channelProperties.highlightValue\"\n            :min-number=\"0\"\n            :max-number=\"(typeof channel.highlightValue) === `string` ? 100 : dmxMax\"\n            wide\n            name=\"highlightValue\" />\n        </LabeledInput>\n\n        <LabeledInput :formstate=\"formstate\" name=\"constant\" label=\"Constant?\">\n          <PropertyInputBoolean\n            v-model=\"channel.constant\"\n            name=\"constant\"\n            label=\"Channel is fixed to default DMX value\" />\n        </LabeledInput>\n\n        <LabeledInput :formstate=\"formstate\" name=\"precedence\" label=\"Precedence\">\n          <PropertyInputSelect\n            v-model=\"channel.precedence\"\n            :schema-property=\"channelProperties.precedence\"\n            name=\"precedence\" />\n        </LabeledInput>\n\n      </div>\n\n      <div class=\"button-bar right\">\n        <button :disabled=\"channel.wizard.show\" type=\"submit\" class=\"primary\">{{ submitButtonTitle }}</button>\n      </div>\n\n    </VueForm>\n\n  </A11yDialog>\n</template>\n\n<style lang=\"scss\" scoped>\n.expand-all,\n.collapse-all {\n  margin-left: 1ex;\n  font-size: 0.8rem;\n}\n\n.existing-channel-input-container ::v-deep section {\n  display: block;\n}\n\n.channel-list {\n  max-height: 400px;\n  padding: 0;\n  margin: 0;\n  overflow-y: auto;\n  list-style: none;\n  background-color: theme-color(card-background);\n  border: 1px solid theme-color(text-secondary);\n\n  legend {\n    display: block;\n    width: calc(100% + 2px);\n    padding: 0;\n    margin: 0 -1px;\n    color: theme-color(text-secondary);\n    border-bottom: 1px solid theme-color(text-secondary);\n  }\n}\n\n.channel-list-item {\n  display: flex;\n  gap: 1ex;\n  align-items: center;\n  padding: 0.5ex 2ex;\n  cursor: pointer;\n  user-select: none;\n  border-bottom: 1px solid theme-color(divider);\n  transition: background-color 0.15s;\n\n  &:where(:has(.channel-checkbox:checked)) {\n    background-color: theme-color(active-background);\n  }\n\n  &:last-child {\n    border-bottom: none;\n  }\n\n  &:hover,\n  &:has(.channel-checkbox:focus-visible) {\n    background-color: theme-color(hover-background);\n  }\n}\n\n.channel-checkbox {\n  flex-shrink: 0;\n  margin: 0;\n  cursor: pointer;\n}\n\n.channel-uuid {\n  font-size: 0.85em;\n  color: theme-color(text-secondary);\n}\n\n@media (min-width: $phone) {\n  #channel-dialog ::v-deep .dialog {\n    width: 80%;\n    max-width: 700px;\n  }\n}\n</style>\n\n<script>\nimport scrollIntoView from 'scroll-into-view';\nimport { v4 as uuidv4 } from 'uuid';\nimport { objectProp } from 'vue-ts-types';\nimport { capabilityTypes, channelProperties } from '../../../lib/schema-properties.js';\nimport {\n  constants,\n  getEmptyCapability,\n  getEmptyFineChannel,\n  getEmptyFormState,\n  getSanitizedChannel,\n  isCapabilityChanged,\n  isChannelChanged,\n} from '../../assets/scripts/editor-utilities.js';\nimport A11yDialog from '../A11yDialog.vue';\nimport LabeledInput from '../LabeledInput.vue';\nimport PropertyInputBoolean from '../PropertyInputBoolean.vue';\nimport PropertyInputEntity from '../PropertyInputEntity.vue';\nimport PropertyInputSelect from '../PropertyInputSelect.vue';\nimport PropertyInputText from '../PropertyInputText.vue';\nimport EditorCapability from './EditorCapability.vue';\nimport EditorCapabilityWizard from './EditorCapabilityWizard.vue';\n\nexport default {\n  components: {\n    A11yDialog,\n    EditorCapability,\n    EditorCapabilityWizard,\n    LabeledInput,\n    PropertyInputBoolean,\n    PropertyInputEntity,\n    PropertyInputSelect,\n    PropertyInputText,\n  },\n  props: {\n    channel: objectProp().required,\n    fixture: objectProp().required,\n  },\n  emits: {\n    'channel-changed': () => true,\n    'remove-channel': (channelId) => true,\n    'reset-channel': () => true,\n  },\n  data() {\n    return {\n      formstate: getEmptyFormState(),\n      restored: false,\n      channelChanged: false,\n      channelProperties,\n      singleColors: capabilityTypes.ColorIntensity.properties.color.enum,\n      constants,\n      selectedChannelUuids: [],\n    };\n  },\n  computed: {\n    dmxMax() {\n      return Math.pow(256, this.channel.dmxValueResolution) - 1;\n    },\n    currentMode() {\n      const uuid = this.channel.modeId;\n      const modeIndex = this.fixture.modes.findIndex((mode) => mode.uuid === uuid);\n      return this.fixture.modes[modeIndex];\n    },\n    currentModeUnchosenChannelUuids() {\n      return Object.keys(this.fixture.availableChannels).filter(\n        (channelUuid) => !this.currentMode.channels.includes(channelUuid),\n      );\n    },\n    currentModeUnchosenChannels() {\n      return this.currentModeUnchosenChannelUuids.map((channelUuid) => ({\n        inputId: `unchosen-channel-${channelUuid}`,\n        uuid: channelUuid,\n        name: this.getChannelName(channelUuid),\n        showUuid: !this.isChannelNameUnique(channelUuid),\n        isSelected: this.isChannelSelected(channelUuid),\n      }));\n    },\n    selectedChannelUuidsString() {\n      return this.selectedChannelUuids.join(',');\n    },\n    currentModeDisplayName() {\n      let modeName = `#${this.fixture.modes.indexOf(this.currentMode) + 1}`;\n      if (this.currentMode.shortName) {\n        modeName = `\"${this.currentMode.shortName}\"`;\n      }\n      else if (this.currentMode.name) {\n        modeName = `\"${this.currentMode.name}\"`;\n      }\n      return modeName;\n    },\n    title() {\n      if (this.channel.editMode === 'add-existing') {\n        return `Add channel to mode ${this.currentModeDisplayName}`;\n      }\n\n      if (this.channel.editMode === 'create') {\n        return 'Create new channel';\n      }\n\n      if (this.channel.editMode === 'edit-duplicate') {\n        return 'Edit channel duplicate';\n      }\n\n      return 'Edit channel';\n    },\n    areCapabilitiesChanged() {\n      return this.channel.capabilities.some(\n        (capability) => isCapabilityChanged(capability),\n      );\n    },\n    submitButtonTitle() {\n      if (this.channel.editMode === 'add-existing') {\n        const count = this.selectedChannelUuids.length;\n        return count <= 1 ? 'Add channel' : `Add ${count} channels`;\n      }\n\n      if (this.channel.editMode === 'create') {\n        return 'Create channel';\n      }\n\n      return 'Save changes';\n    },\n  },\n  watch: {\n    channel: {\n      handler() {\n        if (isChannelChanged(this.channel)) {\n          this.$emit('channel-changed');\n          this.channelChanged = true;\n        }\n      },\n      deep: true,\n    },\n  },\n  methods: {\n    setEditModeCreate() {\n      this.channel.editMode = 'create';\n      this.channel.uuid = uuidv4();\n    },\n\n    getChannelName(channelUuid) {\n      const fixtureEditor = this.$parent;\n      return fixtureEditor.getChannelName(channelUuid);\n    },\n\n    isChannelNameUnique(channelUuid) {\n      const fixtureEditor = this.$parent;\n      return fixtureEditor.isChannelNameUnique(channelUuid);\n    },\n\n    isChannelSelected(channelUuid) {\n      return this.selectedChannelUuids.includes(channelUuid);\n    },\n\n    modeHasChannel(channelUuid) {\n      return this.currentMode.channels.includes(channelUuid);\n    },\n\n    toggleChannelSelection(channelUuid) {\n      if (this.isChannelSelected(channelUuid)) {\n        this.deselectChannel(channelUuid);\n      }\n      else {\n        this.selectChannel(channelUuid);\n      }\n\n      this.channelChanged = true;\n    },\n\n    deselectChannel(channelUuid) {\n      const deselectedChannel = this.fixture.availableChannels[channelUuid];\n      const isFineChannel = 'coarseChannelId' in deselectedChannel;\n\n      // Deselect the channel\n      this.selectedChannelUuids = this.selectedChannelUuids.filter((uuid) => uuid !== channelUuid);\n\n      if (isFineChannel) {\n        // Deselect all finer channels\n        this.selectedChannelUuids = this.selectedChannelUuids.filter((uuid) => {\n          const channel = this.fixture.availableChannels[uuid];\n          return (\n            !('coarseChannelId' in channel)\n            || channel.coarseChannelId !== deselectedChannel.coarseChannelId\n            || channel.resolution < deselectedChannel.resolution\n          );\n        });\n        return;\n      }\n\n      // Deselect all fine channels belonging to this coarse channel\n      this.selectedChannelUuids = this.selectedChannelUuids.filter((uuid) => {\n        const channel = this.fixture.availableChannels[uuid];\n        return !('coarseChannelId' in channel) || channel.coarseChannelId !== channelUuid;\n      });\n    },\n\n    selectChannel(channelUuid) {\n      if (this.isChannelSelected(channelUuid)) {\n        return;\n      }\n\n      const selectedChannel = this.fixture.availableChannels[channelUuid];\n      const isFineChannel = 'coarseChannelId' in selectedChannel;\n\n      if (!isFineChannel) {\n        this.selectedChannelUuids.push(channelUuid);\n        return;\n      }\n\n      // Add the coarse channel if not already selected\n      const coarseChannelId = selectedChannel.coarseChannelId;\n      if (!this.isChannelSelected(coarseChannelId) && !this.modeHasChannel(coarseChannelId)) {\n        this.selectedChannelUuids.push(coarseChannelId);\n      }\n\n      // Add all finer channels between coarse and selected fine channel\n      const currentResolution = selectedChannel.resolution;\n      for (const uuid of this.currentModeUnchosenChannelUuids) {\n        const channel = this.fixture.availableChannels[uuid];\n        if (\n          'coarseChannelId' in channel\n          && channel.coarseChannelId === coarseChannelId\n          && channel.resolution < currentResolution\n          && !this.isChannelSelected(uuid)\n          && !this.modeHasChannel(uuid)\n        ) {\n          this.selectedChannelUuids.push(uuid);\n        }\n      }\n\n      this.selectedChannelUuids.push(channelUuid);\n    },\n\n    async onChannelDoubleClick(channelUuid) {\n      // Select the channel if not already selected\n      if (!this.isChannelSelected(channelUuid)) {\n        this.toggleChannelSelection(channelUuid);\n      }\n\n      if (this.selectedChannelUuids.some((uuid) => uuid !== channelUuid)) {\n        // another channel is already selected, do not submit on double-click\n        return;\n      }\n\n      // wait until validation state is updated\n      await this.$nextTick();\n      this.onSubmit();\n    },\n\n    async onChannelDialogOpen() {\n      if (this.restored) {\n        this.restored = false;\n        return;\n      }\n\n      if (this.channel.editMode === 'add-existing' && this.currentModeUnchosenChannels.length === 0) {\n        this.channel.editMode = 'create';\n      }\n      else if (this.channel.editMode === 'add-existing') {\n        this.channel.uuid = '';\n        this.selectedChannelUuids = [];\n      }\n      else if (this.channel.editMode === 'edit-all' || this.channel.editMode === 'edit-duplicate') {\n        this.copyPropertiesFromChannel(this.fixture.availableChannels[this.channel.uuid]);\n      }\n\n      // after dialog is opened\n      await this.$nextTick();\n      this.channelChanged = false;\n    },\n\n    copyPropertiesFromChannel(channel) {\n      for (const property of Object.keys(channel)) {\n        this.channel[property] = structuredClone(channel[property]);\n      }\n    },\n\n    async onChannelDialogClose() {\n      if (this.channel.editMode === '') {\n        // saving did already manage everything\n        return;\n      }\n\n      if (this.channelChanged && !window.confirm('Do you want to lose the entered channel data?')) {\n        await this.$nextTick();\n        this.restored = true;\n        this.$refs.channelDialog.show();\n        return;\n      }\n\n      this.resetChannelForm();\n    },\n\n    onChannelNameChanged(channelName) {\n      if (this.areCapabilitiesChanged || channelName === '') {\n        return;\n      }\n\n      const capability = this.channel.capabilities[0];\n\n      const matchingColor = this.singleColors.find(\n        (color) => channelName.toLowerCase().includes(color.toLowerCase()),\n      );\n      if (matchingColor) {\n        capability.type = 'ColorIntensity';\n        capability.typeData.color = matchingColor;\n        return;\n      }\n\n      const capabilityTypeSuggestions = {\n        NoFunction: /^(?:no function|nothing|reserved)$/i,\n        StrobeSpeed: /^(?:strobe speed|strobe rate)$/i,\n        StrobeDuration: /^(?:strobe duration|flash duration)$/i,\n        Intensity: /^(?:intensity|dimmer|master dimmer)$/i,\n        ColorTemperature: /^(?:colou?r temperature(?: correction)?|ctc|cto|ctb)$/i,\n        Pan: /^(?:pan|horizontal movement)$/i,\n        Tilt: /^(?:tilt|vertical movement)$/i,\n        PanTiltSpeed: /^(?:pan ?\\/? ?tilt|movement) (?:speed|time|duration)$/i,\n        WheelShake: /\\bshake\\b/i,\n        WheelSlotRotation: /gobo ?\\d* (?:rotation|index)/i,\n        WheelRotation: /wheels? ?\\d* (?:rotation|index)/i,\n        WheelSlot: /wheel|dis[ck]|(?:gobos? ?\\d*$)/i,\n        EffectSpeed: /^(?:effect|program|macro) speed$/i,\n        EffectDuration: /^(?:effect|program|macro) (?:time|duration)$/i,\n        SoundSensitivity: /^(?:sound|mic|microphone) sensitivity$/i,\n        Focus: /^focus$/i,\n        Zoom: /^zoom$/i,\n        Iris: /^iris$/i,\n        Frost: /^frost$/i,\n        Fog: /^(?:fog|haze)$/i,\n        FogOutput: /^(?:fog (?:output|intensity|emission)|pump)$/i,\n        Speed: /^.*?speed$/i,\n        Time: /^.*?(?:time|duration)$/i,\n      };\n\n      const matchingType = Object.keys(capabilityTypeSuggestions).find(\n        (type) => capabilityTypeSuggestions[type].test(channelName),\n      );\n\n      if (matchingType) {\n        capability.type = matchingType;\n      }\n    },\n\n    onResolutionChanged() {\n      if (this.channel.dmxValueResolution > this.channel.resolution) {\n        this.channel.dmxValueResolution = this.channel.resolution;\n      }\n    },\n\n    /**\n     * Call onEndUpdated() on the last capability component with non-empty\n     * DMX end value to add / remove an empty capability at the end.\n     */\n    async onDmxValueResolutionChanged() {\n      await this.$nextTick();\n\n      let index = this.channel.capabilities.length - 1;\n      while (index >= 0) {\n        const capability = this.channel.capabilities[index];\n        if (capability.dmxRange !== null && capability.dmxRange[1] !== null && !this.channel.wizard.show) {\n          this.$refs.capabilities[index].onEndUpdated();\n          break;\n        }\n        index--;\n      }\n    },\n\n    onSubmit() {\n      if (this.channel.wizard.show) {\n        return;\n      }\n\n      if (this.formstate.$invalid) {\n        const invalidFields = document.querySelectorAll('#channel-dialog .vf-field-invalid');\n\n        for (let index = 0; index < invalidFields.length; index++) {\n          const enclosingDetails = invalidFields[index].closest('details:not([open])');\n\n          if (enclosingDetails) {\n            enclosingDetails.open = true;\n\n            // current field could be enclosed another time, so repeat\n            index--;\n          }\n        }\n\n        const scrollContainer = invalidFields[0].closest('.dialog');\n        scrollIntoView(invalidFields[0], {\n          time: 300,\n          align: {\n            top: 0,\n            left: 0,\n            topOffset: 100,\n          },\n          isScrollable: (target) => target === scrollContainer,\n        }, () => invalidFields[0].focus());\n\n        return;\n      }\n\n      for (const capability of this.$refs.capabilities) {\n        capability.cleanCapabilityData();\n      }\n\n      const actions = {\n        'create': this.saveCreatedChannel,\n        'edit-all': this.saveEditedChannel,\n        'edit-duplicate': this.saveDuplicatedChannel,\n        'add-existing': this.addExistingChannel,\n      };\n\n      if (this.channel.editMode in actions) {\n        actions[this.channel.editMode]();\n      }\n\n      this.resetChannelForm();\n    },\n\n    saveCreatedChannel() {\n      this.$set(this.fixture.availableChannels, this.channel.uuid, getSanitizedChannel(this.channel));\n      this.currentMode.channels.push(this.channel.uuid);\n\n      this.addFineChannels(this.channel, constants.RESOLUTION_16BIT, true);\n    },\n\n    saveEditedChannel() {\n      const previousResolution = this.fixture.availableChannels[this.channel.uuid].resolution;\n      this.fixture.availableChannels[this.channel.uuid] = getSanitizedChannel(this.channel);\n\n      if (previousResolution > this.channel.resolution) {\n        for (const channelId of Object.keys(this.fixture.availableChannels)) {\n          const channel = this.fixture.availableChannels[channelId];\n          if (channel.coarseChannelId === this.channel.uuid && channel.resolution > this.channel.resolution) {\n            this.$emit('remove-channel', channelId);\n          }\n        }\n      }\n      else {\n        this.addFineChannels(this.channel, previousResolution + 1, false);\n      }\n    },\n\n    saveDuplicatedChannel() {\n      const oldChannelKey = this.channel.uuid;\n\n      const newChannelKey = uuidv4();\n      const newChannel = getSanitizedChannel(this.channel);\n      newChannel.uuid = newChannelKey;\n      this.$set(this.fixture.availableChannels, newChannelKey, newChannel);\n\n      const fineChannelUuids = this.addFineChannels(newChannel, constants.RESOLUTION_16BIT, false);\n\n      this.currentMode.channels = this.currentMode.channels.map((key) => {\n        if (key === oldChannelKey) {\n          return newChannelKey;\n        }\n\n        // map each old fine channel to the new fine channel\n        const oldFineChannel = this.fixture.availableChannels[key];\n        if (oldFineChannel.coarseChannelId === oldChannelKey) {\n          return fineChannelUuids[oldFineChannel.resolution];\n        }\n\n        // this channel is not affected by the duplicate at all\n        return key;\n      });\n    },\n\n    addExistingChannel() {\n      for (const channelUuid of this.selectedChannelUuids) {\n        if (!this.modeHasChannel(channelUuid)) {\n          this.currentMode.channels.push(channelUuid);\n        }\n      }\n\n      // Reset selection\n      this.selectedChannelUuids = [];\n    },\n\n    /**\n     * @param {object} coarseChannel The channel object of the coarse channel.\n     * @param {number} offset At which resolution should be started.\n     * @param {boolean} [addToMode] If true, the fine channel is pushed to the current mode's channels.\n     * @returns {string[]} Array of added fine channel UUIDs (at the index of their resolution).\n     */\n    addFineChannels(coarseChannel, offset, addToMode) {\n      const addedFineChannelUuids = [];\n\n      for (let index = offset; index <= coarseChannel.resolution; index++) {\n        const fineChannel = getEmptyFineChannel(coarseChannel.uuid, index);\n        this.$set(this.fixture.availableChannels, fineChannel.uuid, getSanitizedChannel(fineChannel));\n        addedFineChannelUuids[index] = fineChannel.uuid;\n\n        if (addToMode) {\n          this.currentMode.channels.push(fineChannel.uuid);\n        }\n      }\n\n      return addedFineChannelUuids;\n    },\n\n    async resetChannelForm() {\n      this.$emit('reset-channel');\n\n      await this.$nextTick();\n      this.formstate._reset(); // resets validation status\n    },\n\n    /**\n     * @param {boolean} show Whether to show or hide the Capability Wizard.\n     */\n    setWizardVisibility(show) {\n      this.channel.wizard.show = show;\n\n      if (!show) {\n        this.onDmxValueResolutionChanged(); // maybe DMX value resolution has been changed while wizard was open\n      }\n    },\n\n    async onWizardClose(insertIndex) {\n      this.setWizardVisibility(false);\n\n      await this.$nextTick();\n      const firstNewCapability = this.$refs.capabilities[insertIndex];\n      const scrollContainer = firstNewCapability.$el.closest('.dialog');\n\n      scrollIntoView(firstNewCapability.$el, {\n        time: 0,\n        align: {\n          top: 0,\n          left: 0,\n          topOffset: 100,\n        },\n        isScrollable: (target) => target === scrollContainer,\n      }, () => firstNewCapability.focus());\n    },\n\n    openDetails() {\n      for (const details of this.$el.querySelectorAll('details')) {\n        details.open = true;\n      }\n    },\n\n    closeDetails() {\n      for (const details of this.$el.querySelectorAll('details')) {\n        details.open = false;\n      }\n    },\n\n    insertEmptyCapability(index) {\n      this.channel.capabilities.splice(index, 0, getEmptyCapability());\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorChooseChannelEditModeDialog.vue",
    "content": "<template>\n  <A11yDialog\n    id=\"choose-channel-edit-mode-dialog\"\n    is-alert-dialog\n    :shown=\"channel.editMode === `edit-?`\"\n    title=\"Edit channel in all modes or just in this one?\"\n    @show=\"onChooseChannelEditModeDialogOpen()\">\n\n    <div class=\"button-bar right\">\n      <button\n        type=\"submit\"\n        class=\"secondary\"\n        @click.prevent=\"chooseChannelEditMode(`edit-duplicate`)\">\n        Only in this mode\n      </button>\n      <button\n        type=\"submit\"\n        class=\"primary\"\n        @click.prevent=\"chooseChannelEditMode(`edit-all`)\">\n        In all modes\n      </button>\n    </div>\n\n  </A11yDialog>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport A11yDialog from '../A11yDialog.vue';\n\nexport default {\n  components: {\n    A11yDialog,\n  },\n  props: {\n    channel: objectProp().required,\n    fixture: objectProp().required,\n  },\n  methods: {\n    onChooseChannelEditModeDialogOpen() {\n      const channelUsedElsewhere = this.fixture.modes.some(\n        (mode) => mode.uuid !== this.channel.modeId && mode.channels.includes(this.channel.uuid),\n      );\n\n      if (channelUsedElsewhere) {\n        // let user first choose if they want to edit all or a duplicate\n        return;\n      }\n\n      // else duplicate makes no sense here -> continue directly\n      this.chooseChannelEditMode('edit-all');\n    },\n    async chooseChannelEditMode(editMode) {\n      // close this dialog\n      this.channel.editMode = '';\n\n      await this.$nextTick();\n\n      // open channel dialog\n      this.channel.editMode = editMode;\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorFileUpload.vue",
    "content": "<template>\n  <input\n    ref=\"fileInput\"\n    :required=\"required\"\n    :name=\"name\"\n    type=\"file\"\n    @change=\"onFileChanged()\">\n</template>\n\n<script>\nimport { anyProp, booleanProp, stringProp } from 'vue-ts-types';\n\nexport default {\n  model: {\n    prop: 'model-value',\n    event: 'update:model-value',\n  },\n  props: {\n    required: booleanProp().withDefault(false),\n    name: stringProp().required,\n    modelValue: anyProp().optional,\n  },\n  emits: {\n    'update:model-value': (value) => true,\n  },\n  watch: {\n    modelValue(newFile) {\n      if (!newFile) {\n        this.$refs.fileInput.value = '';\n      }\n    },\n  },\n  mounted() {\n    this.onFileChanged();\n  },\n  methods: {\n    onFileChanged() {\n      const file = this.$refs.fileInput.files[0];\n\n      if (!file) {\n        this.$emit('update:model-value', undefined);\n        return;\n      }\n\n      this.$emit('update:model-value', file);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorFixtureInformation.vue",
    "content": "<template>\n  <section class=\"fixture-info card\">\n    <h2>Fixture info</h2>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :custom-validators=\"{ 'no-manufacturer-name': fixtureNameIsWithoutManufacturer }\"\n      name=\"fixture-name\"\n      label=\"Name\">\n      <PropertyInputText\n        v-model=\"fixture.name\"\n        :schema-property=\"fixtureProperties.name\"\n        required\n        name=\"fixture-name\" />\n    </LabeledInput>\n\n    <LabeledInput :formstate=\"formstate\" name=\"fixture-shortName\" label=\"Unique short name\">\n      <PropertyInputText\n        v-model=\"fixture.shortName\"\n        :schema-property=\"fixtureProperties.shortName\"\n        name=\"fixture-shortName\"\n        hint=\"defaults to name\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      name=\"fixture-categories\"\n      label=\"Categories\"\n      hint=\"Select and reorder all applicable categories, the most suitable first.\">\n      <EditorCategoryChooser\n        v-model=\"fixture.categories\"\n        :all-categories=\"fixtureProperties.categories.items.enum\"\n        name=\"fixture-categories\"\n        categories-not-empty />\n    </LabeledInput>\n\n    <LabeledInput :formstate=\"formstate\" name=\"comment\" label=\"Comment\">\n      <PropertyInputTextarea\n        v-model=\"fixture.comment\"\n        :schema-property=\"fixtureProperties.comment\"\n        name=\"comment\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      name=\"links\"\n      label=\"Relevant links\">\n      <EditorLinks v-model=\"fixture.links\" name=\"links\" :formstate=\"formstate\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      name=\"rdmModelId\"\n      hint=\"The RDM manufacturer ID is saved per manufacturer.\">\n      <template #label><abbr title=\"Remote Device Management\">RDM</abbr> model ID</template>\n      <PropertyInputNumber\n        v-model=\"fixture.rdmModelId\"\n        :schema-property=\"fixtureProperties.rdm.properties.modelId\"\n        name=\"rdmModelId\" />\n    </LabeledInput>\n\n    <LabeledInput\n      v-if=\"fixture.rdmModelId !== null\"\n      :formstate=\"formstate\"\n      name=\"rdmSoftwareVersion\"\n      label=\"RDM software version\">\n      <PropertyInputText\n        v-model=\"fixture.rdmSoftwareVersion\"\n        :schema-property=\"fixtureProperties.rdm.properties.softwareVersion\"\n        name=\"rdmSoftwareVersion\" />\n    </LabeledInput>\n  </section>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { fixtureProperties } from '../../../lib/schema-properties.js';\nimport LabeledInput from '../LabeledInput.vue';\nimport PropertyInputNumber from '../PropertyInputNumber.vue';\nimport PropertyInputText from '../PropertyInputText.vue';\nimport PropertyInputTextarea from '../PropertyInputTextarea.vue';\nimport EditorCategoryChooser from './EditorCategoryChooser.vue';\nimport EditorLinks from './EditorLinks.vue';\n\nexport default {\n  components: {\n    EditorCategoryChooser,\n    EditorLinks,\n    LabeledInput,\n    PropertyInputNumber,\n    PropertyInputText,\n    PropertyInputTextarea,\n  },\n  props: {\n    fixture: objectProp().required,\n    formstate: objectProp().required,\n    manufacturers: objectProp().required,\n  },\n  data() {\n    return {\n      fixtureProperties,\n    };\n  },\n  computed: {\n    manufacturerName() {\n      if (!this.fixture.useExistingManufacturer) {\n        return this.fixture.newManufacturerName;\n      }\n\n      const manufacturerKey = this.fixture.manufacturerKey;\n\n      if (manufacturerKey === '') {\n        return '';\n      }\n\n      return this.manufacturers[manufacturerKey].name;\n    },\n    fixtureNameIsWithoutManufacturer() {\n      const manufacturerName = this.manufacturerName.trim().toLowerCase();\n      return manufacturerName === '' || !this.fixture.name.trim().toLowerCase().startsWith(manufacturerName);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorLink.vue",
    "content": "<template>\n  <div class=\"link-row\">\n    <select ref=\"linkTypeSelect\" v-model=\"type\">\n      <option\n        v-for=\"linkType of linkTypes\"\n        :key=\"linkType\"\n        :value=\"linkType\">{{ linkTypeNames[linkType] }}</option>\n    </select>\n\n    <OflSvg :name=\"linkTypeIconNames[link.type]\" />\n\n    <Validate :state=\"formstate\" tag=\"span\">\n      <PropertyInputText\n        v-model=\"url\"\n        :name=\"`links-${link.uuid}`\"\n        :schema-property=\"schemaDefinitions.urlString\"\n        type=\"url\"\n        :hint=\"placeholder\"\n        required />\n    </Validate>\n\n    <button\n      v-if=\"canRemove\"\n      type=\"button\"\n      class=\"icon-button\"\n      title=\"Remove link\"\n      @click.prevent=\"$emit(`remove`)\">\n      <OflSvg name=\"close\" />\n    </button>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.link-row {\n  margin-bottom: 4px;\n\n  select {\n    width: 17ex;\n    margin-right: 1ex;\n  }\n\n  & > .icon {\n    margin-right: 0.5ex;\n  }\n}\n\n.icon-button {\n  margin-left: 0.5ex;\n}\n</style>\n\n<script>\nimport { booleanProp, objectProp } from 'vue-ts-types';\nimport { linksProperties, schemaDefinitions } from '../../../lib/schema-properties.js';\nimport fixtureLinkTypes from '../../assets/scripts/fixture-link-types.js';\nimport PropertyInputText from '../PropertyInputText.vue';\n\nconst placeholders = {\n  manual: 'e.g. https://example.org/fixture/manual.pdf',\n  productPage: 'e.g. https://example.org/fixture',\n  video: 'e.g. https://www.youtube.com/watch?v=dQw4w9WgXcQ',\n  other: 'e.g. https://example.org/relevant-page',\n};\n\nexport default {\n  components: {\n    PropertyInputText,\n  },\n  props: {\n    link: objectProp().required,\n    canRemove: booleanProp().required,\n    formstate: objectProp().required,\n  },\n  emits: {\n    'set-type': (type) => true,\n    'set-url': (url) => true,\n    'remove': () => true,\n  },\n  data() {\n    const { linkTypeIconNames, linkTypeNames } = fixtureLinkTypes;\n    return {\n      schemaDefinitions,\n      linkTypes: Object.keys(linksProperties),\n      linkTypeIconNames,\n      linkTypeNames,\n    };\n  },\n  computed: {\n    type: {\n      get() {\n        return this.link.type;\n      },\n      set(type) {\n        this.$emit('set-type', type);\n      },\n    },\n    url: {\n      get() {\n        return this.link.url;\n      },\n      set(url) {\n        this.$emit('set-url', url);\n      },\n    },\n    placeholder() {\n      return placeholders[this.type];\n    },\n  },\n  methods: {\n    /** @public */\n    focus() {\n      this.$refs.linkTypeSelect.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorLinks.vue",
    "content": "<template>\n  <div class=\"links\">\n    <EditorLink\n      v-for=\"link of modelValue\"\n      :key=\"link.uuid\"\n      ref=\"links\"\n      :link=\"link\"\n      :can-remove=\"modelValue.length > 1\"\n      :formstate=\"formstate\"\n      @set-type=\"updateLinkProperty(link, `type`, $event)\"\n      @set-url=\"updateLinkProperty(link, `url`, $event)\"\n      @remove=\"removeLink(link)\" />\n\n    <a href=\"#add-link\" @click.prevent=\"addLink()\">\n      <OflSvg name=\"plus\" />\n      Add link\n    </a>\n  </div>\n</template>\n\n<script>\nimport { arrayProp, objectProp } from 'vue-ts-types';\nimport { getEmptyLink } from '../../assets/scripts/editor-utilities.js';\nimport EditorLink from './EditorLink.vue';\n\nexport default {\n  components: {\n    EditorLink,\n  },\n  inheritAttrs: false,\n  model: {\n    prop: 'model-value',\n    event: 'update:model-value',\n  },\n  props: {\n    modelValue: arrayProp().required,\n    formstate: objectProp().required,\n  },\n  emits: {\n    'update:model-value': (value) => true,\n  },\n  methods: {\n    async addLink() {\n      const newLinks = [...this.modelValue, getEmptyLink()];\n      this.$emit('update:model-value', newLinks);\n\n      await this.$nextTick();\n      this.$refs.links[newLinks.length - 1].focus();\n    },\n    updateLinkProperty(updateLink, key, value) {\n      const updatedLink = {\n        ...updateLink,\n        [key]: value,\n      };\n\n      this.$emit('update:model-value', this.modelValue.map(\n        (link) => (link === updateLink ? updatedLink : link),\n      ));\n    },\n    removeLink(removeLink) {\n      this.$emit('update:model-value', this.modelValue.filter(\n        (link) => link !== removeLink,\n      ));\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorManufacturer.vue",
    "content": "<template>\n  <section class=\"manufacturer card\">\n    <h2>Manufacturer</h2>\n\n    <section v-if=\"fixture.useExistingManufacturer\">\n      <LabeledInput :formstate=\"formstate\" name=\"manufacturerKey\" label=\"Choose from list\">\n        <select\n          ref=\"existingManufacturerSelect\"\n          v-model=\"fixture.manufacturerKey\"\n          :class=\"{ empty: fixture.manufacturerKey === `` }\"\n          required\n          name=\"manufacturerKey\">\n\n          <option value=\"\" disabled>Please select a manufacturer</option>\n\n          <template v-for=\"(manufacturer, manufacturerKey) of manufacturers\">\n            <option v-if=\"manufacturerKey !== `$schema`\" :key=\"manufacturerKey\" :value=\"manufacturerKey\">\n              {{ manufacturer.name }}\n            </option>\n          </template>\n\n        </select>\n      </LabeledInput>\n\n      <div>or <a href=\"#add-new-manufacturer\" @click.prevent=\"switchManufacturer(false)\">add a new manufacturer</a></div>\n    </section>\n\n    <div v-else>\n      <LabeledInput :formstate=\"formstate\" name=\"new-manufacturer-name\" label=\"Name\">\n        <PropertyInputText\n          ref=\"newManufacturerNameInput\"\n          v-model=\"fixture.newManufacturerName\"\n          :schema-property=\"manufacturerProperties.name\"\n          required\n          name=\"new-manufacturer-name\" />\n      </LabeledInput>\n\n      <LabeledInput :formstate=\"formstate\" name=\"new-manufacturer-website\" label=\"Website\">\n        <PropertyInputText\n          v-model=\"fixture.newManufacturerWebsite\"\n          :schema-property=\"manufacturerProperties.website\"\n          type=\"url\"\n          name=\"new-manufacturer-website\" />\n      </LabeledInput>\n\n      <LabeledInput :formstate=\"formstate\" name=\"new-manufacturer-comment\" label=\"Comment\">\n        <PropertyInputTextarea\n          v-model=\"fixture.newManufacturerComment\"\n          :schema-property=\"manufacturerProperties.comment\"\n          name=\"new-manufacturer-comment\" />\n      </LabeledInput>\n\n      <LabeledInput :formstate=\"formstate\" name=\"new-manufacturer-rdmId\">\n        <template #label><abbr title=\"Remote Device Management\">RDM</abbr> manufacturer ID</template>\n        <PropertyInputNumber\n          v-model=\"fixture.newManufacturerRdmId\"\n          :schema-property=\"manufacturerProperties.rdmId\"\n          name=\"new-manufacturer-rdmId\" />\n      </LabeledInput>\n\n      <div>or <a href=\"#use-existing-manufacturer\" @click.prevent=\"switchManufacturer(true)\">choose an existing manufacturer</a></div>\n    </div>\n  </section>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { manufacturerProperties } from '../../../lib/schema-properties.js';\nimport LabeledInput from '../LabeledInput.vue';\nimport PropertyInputNumber from '../PropertyInputNumber.vue';\nimport PropertyInputText from '../PropertyInputText.vue';\nimport PropertyInputTextarea from '../PropertyInputTextarea.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputNumber,\n    PropertyInputText,\n    PropertyInputTextarea,\n  },\n  props: {\n    fixture: objectProp().required,\n    formstate: objectProp().required,\n    manufacturers: objectProp().required,\n  },\n  data() {\n    return {\n      manufacturerProperties,\n    };\n  },\n  watch: {\n    async 'fixture.useExistingManufacturer'(useExisting) {\n      await this.$nextTick();\n      this.$refs[useExisting ? 'existingManufacturerSelect' : 'newManufacturerNameInput'].focus();\n    },\n  },\n  methods: {\n    switchManufacturer(useExisting) {\n      this.fixture.useExistingManufacturer = useExisting;\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorMode.vue",
    "content": "<template>\n  <section :data-mode-uuid=\"mode.uuid\" class=\"fixture-mode card\">\n\n    <a\n      v-if=\"fixture.modes.length > 1\"\n      href=\"#remove-mode\"\n      class=\"icon-button close\"\n      @click.prevent=\"$emit(`remove`)\">\n      Remove mode\n      <OflSvg name=\"close\" />\n    </a>\n\n    <h2>Mode #{{ index + 1 }}</h2>\n\n    <LabeledInput :formstate=\"formstate\" :name=\"`mode-${index}-name`\" label=\"Name\">\n      <PropertyInputText\n        ref=\"firstInput\"\n        v-model=\"mode.name\"\n        :name=\"`mode-${index}-name`\"\n        :schema-property=\"schemaDefinitions.modeNameString.allOf[1]\"\n        required\n        no-mode-name\n        hint=\"e.g. Extended\"\n        title=\"The name must not contain the word 'mode'.\" />\n    </LabeledInput>\n\n    <LabeledInput :formstate=\"formstate\" :name=\"`mode-${index}-shortName`\" label=\"Unique short name\">\n      <PropertyInputText\n        v-model=\"mode.shortName\"\n        :name=\"`mode-${index}-shortName`\"\n        :schema-property=\"schemaDefinitions.modeNameString.allOf[1]\"\n        no-mode-name\n        hint=\"e.g. ext; defaults to name\"\n        title=\"The short name must not contain the word 'mode'.\" />\n    </LabeledInput>\n\n    <LabeledInput\n      v-if=\"fixture.rdmModelId !== null\"\n      :formstate=\"formstate\"\n      :name=\"`mode-${index}-rdmPersonalityIndex`\"\n      label=\"RDM personality index\">\n      <PropertyInputNumber\n        v-model=\"mode.rdmPersonalityIndex\"\n        :name=\"`mode-${index}-rdmPersonalityIndex`\"\n        :schema-property=\"modeProperties.rdmPersonalityIndex\" />\n    </LabeledInput>\n\n    <h3>Physical override</h3>\n\n    <label>\n      <input\n        v-model=\"mode.enablePhysicalOverride\"\n        type=\"checkbox\"\n        class=\"enable-physical-override\">\n      Override fixture's physical data in this mode\n    </label>\n\n    <section class=\"physical-override\">\n      <EditorPhysical\n        v-if=\"mode.enablePhysicalOverride\"\n        v-model=\"mode.physical\"\n        :formstate=\"formstate\"\n        :name-prefix=\"`mode-${index}`\" />\n    </section>\n\n    <h3>DMX channels</h3>\n\n    <Validate\n      :state=\"formstate\"\n      :custom=\"{ 'no-empty-channel-list': channelListNotEmpty }\"\n      tag=\"div\"\n      class=\"mode-channels\">\n      <input v-model=\"mode.channels\" :name=\"`mode-${index}-channels`\" type=\"hidden\">\n      <Draggable :list=\"mode.channels\" v-bind=\"dragOptions\">\n        <TransitionGroup class=\"mode-channels\" tag=\"ol\">\n          <li\n            v-for=\"(channelUuid, channelIndex) of mode.channels\"\n            :key=\"channelUuid\"\n            :value=\"channelIndex + 1\"\n            :data-channel-uuid=\"channelUuid\">\n\n            <span class=\"channel-name\">{{ getChannelName(channelUuid) }}</span>\n\n            <code v-if=\"!isChannelNameUnique(channelUuid)\" class=\"channel-uuid\"> {{ channelUuid }}</code>\n\n            <span class=\"channel-buttons\">\n              <button\n                type=\"button\"\n                title=\"Drag or press ↓↑ to change channel order\"\n                class=\"drag-handle icon-button\"\n                @keyup.up.prevent=\"moveChannel(channelUuid, -1)\"\n                @keyup.down.prevent=\"moveChannel(channelUuid, 1)\"\n                @click.prevent>\n                <OflSvg name=\"move\" />\n              </button>\n\n              <button\n                v-if=\"!isFineChannel(channelUuid)\"\n                type=\"button\"\n                class=\"icon-button\"\n                title=\"Edit channel\"\n                @click.prevent=\"editChannel(channelUuid)\">\n                <OflSvg name=\"pencil\" />\n              </button>\n\n              <button\n                type=\"button\"\n                class=\"icon-button\"\n                title=\"Remove channel\"\n                @click.prevent=\"removeChannel(channelUuid)\">\n                <OflSvg name=\"close\" />\n              </button>\n            </span>\n\n          </li>\n        </TransitionGroup>\n      </Draggable>\n      <FieldMessages\n        :state=\"formstate\"\n        :name=\"`mode-${index}-channels`\"\n        show=\"$submitted\"\n        tag=\"div\"\n        class=\"error-message\">\n        <template #no-empty-channel-list>\n          <div>A mode must contain at least one channel.</div>\n        </template>\n      </FieldMessages>\n    </Validate>\n\n    <a href=\"#add-channel\" class=\"button primary\" @click.prevent=\"addChannel()\">add channel</a>\n\n  </section>\n</template>\n\n<style lang=\"scss\" scoped>\n.fixture-mode ::v-deep section {\n  flex-direction: column;\n\n  & > .label {\n    flex-basis: auto;\n  }\n}\n\n.mode-channels {\n  padding-top: 4px;\n  padding-bottom: 4px;\n  margin: 0 0 1ex;\n\n  & li {\n    position: relative;\n  }\n\n  & button:focus {\n    opacity: 1;\n  }\n\n  & .channel-buttons {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    display: flex;\n    align-items: center;\n    background-color: theme-color(card-background, 0%);\n    transition: background-color 0.1s, box-shadow 0.1s;\n\n    & button {\n      opacity: 0;\n      transition: opacity 0.1s;\n    }\n  }\n\n  // has to be a separate rule because older browsers would ignore the whole rule\n  & .channel-buttons:focus-within {\n    background-color: theme-color(card-background);\n    box-shadow: -1ex 0 1ex 0.5ex theme-color(card-background);\n\n    & button {\n      opacity: 1;\n    }\n  }\n\n  & li:hover .channel-buttons,\n  & li.sortable-chosen .channel-buttons,\n  & li.sortable-ghost .channel-buttons {\n    background-color: theme-color(card-background);\n    box-shadow: -1ex 0 1ex 0.5ex theme-color(card-background);\n\n    & button {\n      opacity: 1;\n    }\n  }\n\n  & .drag-handle {\n    cursor: grab;\n  }\n}\n</style>\n\n<script>\nimport { numberProp, objectProp } from 'vue-ts-types';\nimport Draggable from 'vuedraggable';\nimport { modeProperties, schemaDefinitions } from '../../../lib/schema-properties.js';\nimport { constants } from '../../assets/scripts/editor-utilities.js';\nimport LabeledInput from '../LabeledInput.vue';\nimport PropertyInputNumber from '../PropertyInputNumber.vue';\nimport PropertyInputText from '../PropertyInputText.vue';\nimport EditorPhysical from './EditorPhysical.vue';\n\nexport default {\n  components: {\n    Draggable,\n    EditorPhysical,\n    LabeledInput,\n    PropertyInputNumber,\n    PropertyInputText,\n  },\n  props: {\n    mode: objectProp().required,\n    index: numberProp().required,\n    fixture: objectProp().required,\n    formstate: objectProp().required,\n  },\n  emits: {\n    'remove': () => true,\n    'open-channel-editor': (payload) => true,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      modeProperties,\n      dragOptions: {\n        animation: 200,\n        handle: '.drag-handle',\n        emptyInsertThreshold: 20,\n        group: {\n          name: 'mode',\n          pull: 'clone',\n          put: (to, from, dragElement, event) => {\n            if (from === to) {\n              return false;\n            }\n\n            const channelUuid = dragElement.getAttribute('data-channel-uuid');\n            const modeUuid = to.el.closest('.fixture-mode').getAttribute('data-mode-uuid');\n            const targetMode = this.fixture.modes.find((mode) => mode.uuid === modeUuid);\n\n            if (targetMode.channels.includes(channelUuid)) {\n              // channel already in target mode\n              return false;\n            }\n\n            const channel = this.fixture.availableChannels[channelUuid];\n            if (!('coarseChannelId' in channel)) {\n              // normal channels don't need any more validation\n              return true;\n            }\n\n            if (!targetMode.channels.includes(channel.coarseChannelId)) {\n              // fine channels need their coarse channel\n              return false;\n            }\n\n            if (channel.resolution === constants.RESOLUTION_16BIT) {\n              // next coarser channel is coarse channel, which is in target mode\n              return true;\n            }\n\n            // return whether next coarser channel can be found in target mode\n            return targetMode.channels.some((uuid) => {\n              const otherChannel = this.fixture.availableChannels[uuid];\n              return otherChannel.coarseChannelId === channel.coarseChannelId && otherChannel.resolution === channel.resolution - 1;\n            });\n          },\n          revertClone: true,\n        },\n      },\n    };\n  },\n  computed: {\n    fixtureEditor() {\n      const vueForm = this.$parent;\n      return vueForm.$parent;\n    },\n    channelListNotEmpty() {\n      return this.mode.channels.length > 0;\n    },\n  },\n  mounted() {\n    if (this.$root._oflRestoreComplete) {\n      this.$refs.firstInput.focus();\n    }\n  },\n  methods: {\n    getChannelName(channelUuid) {\n      return this.fixtureEditor.getChannelName(channelUuid);\n    },\n    editChannel(channelUuid) {\n      this.$emit('open-channel-editor', {\n        modeId: this.mode.uuid,\n        editMode: 'edit-?',\n        uuid: channelUuid,\n      });\n    },\n    addChannel() {\n      this.$emit('open-channel-editor', {\n        modeId: this.mode.uuid,\n        editMode: 'add-existing',\n      });\n    },\n    isChannelNameUnique(channelUuid) {\n      return this.fixtureEditor.isChannelNameUnique(channelUuid);\n    },\n    isFineChannel(channelUuid) {\n      return 'coarseChannelId' in this.fixture.availableChannels[channelUuid];\n    },\n    moveChannel(channelUuid, delta) {\n      const channelIndex = this.mode.channels.indexOf(channelUuid);\n      const newIndex = channelIndex + delta;\n      if (newIndex < 0 || newIndex >= this.mode.channels.length) {\n        return;\n      }\n\n      this.mode.channels.splice(channelIndex, 1);\n      this.mode.channels.splice(newIndex, 0, channelUuid);\n    },\n    removeChannel(channelUuid) {\n      const channel = this.fixture.availableChannels[channelUuid];\n\n      // first remove the finer channels if any\n      let coarseChannelId = channelUuid;\n      let resolution = constants.RESOLUTION_8BIT;\n      if (this.isFineChannel(channelUuid)) {\n        coarseChannelId = channel.coarseChannelId;\n        resolution = channel.resolution;\n      }\n\n      for (const otherChannel of Object.values(this.fixture.availableChannels)) {\n        if (otherChannel.coarseChannelId === coarseChannelId && otherChannel.resolution > resolution) {\n          this.fixtureEditor.removeChannel(otherChannel.uuid, this.mode.uuid);\n        }\n      }\n\n      // then remove the channel itself\n      this.fixtureEditor.removeChannel(channelUuid, this.mode.uuid);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorPhysical.vue",
    "content": "<template>\n  <div>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`${namePrefix}-physical-dimensions`\"\n      label=\"Dimensions\">\n      <PropertyInputDimensions\n        ref=\"firstInput\"\n        v-model=\"localPhysical.dimensions\"\n        :name=\"`${namePrefix}-physical-dimensions`\"\n        :schema-property=\"schemaDefinitions.dimensionsXYZ\"\n        :hints=\"[`width`, `height`, `depth`]\"\n        :formstate=\"formstate\"\n        unit=\"mm\" />\n    </LabeledInput>\n\n    <LabeledInput :formstate=\"formstate\" :name=\"`${namePrefix}-physical-weight`\" label=\"Weight\">\n      <PropertyInputNumber\n        v-model=\"localPhysical.weight\"\n        :name=\"`${namePrefix}-physical-weight`\"\n        :schema-property=\"physicalProperties.weight\" /> kg\n    </LabeledInput>\n\n    <LabeledInput :formstate=\"formstate\" :name=\"`${namePrefix}-physical-power`\" label=\"Power\">\n      <PropertyInputNumber\n        v-model=\"localPhysical.power\"\n        :name=\"`${namePrefix}-physical-power`\"\n        :schema-property=\"physicalProperties.power\" /> W\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`${namePrefix}-physical-DMXconnector`\"\n      label=\"DMX connector\">\n      <PropertyInputSelect\n        v-model=\"localPhysical.DMXconnector\"\n        :name=\"`${namePrefix}-physical-DMXconnector`\"\n        :schema-property=\"physicalProperties.DMXconnector\"\n        addition-hint=\"other DMX connector\" />\n      <Validate\n        v-if=\"modelValue.DMXconnector === `[add-value]`\"\n        :state=\"formstate\"\n        tag=\"span\">\n        <PropertyInputText\n          ref=\"newDmxConnectorInput\"\n          v-model=\"localPhysical.DMXconnectorNew\"\n          :name=\"`${namePrefix}-physical-DMXconnectorNew`\"\n          :schema-property=\"schemaDefinitions.nonEmptyString\"\n          required\n          hint=\"other DMX connector\"\n          class=\"addition\" />\n      </Validate>\n    </LabeledInput>\n\n    <h4>Bulb</h4>\n\n    <LabeledInput :formstate=\"formstate\" :name=\"`${namePrefix}-physical-bulb-type`\" label=\"Bulb type\">\n      <PropertyInputText\n        v-model=\"localPhysical.bulb.type\"\n        :name=\"`${namePrefix}-physical-bulb-type`\"\n        :schema-property=\"physicalBulbProperties.type\"\n        hint=\"e.g. LED\" />\n    </LabeledInput>\n\n    <LabeledInput :formstate=\"formstate\" :name=\"`${namePrefix}-physical-bulb-colorTemperature`\" label=\"Color temperature\">\n      <PropertyInputNumber\n        v-model=\"localPhysical.bulb.colorTemperature\"\n        :name=\"`${namePrefix}-physical-bulb-colorTemperature`\"\n        :schema-property=\"physicalBulbProperties.colorTemperature\" /> K\n    </LabeledInput>\n\n    <LabeledInput :formstate=\"formstate\" :name=\"`${namePrefix}-physical-bulb-lumens`\" label=\"Lumens\">\n      <PropertyInputNumber\n        v-model=\"localPhysical.bulb.lumens\"\n        :name=\"`${namePrefix}-physical-bulb-lumens`\"\n        :schema-property=\"physicalBulbProperties.lumens\" /> lm\n    </LabeledInput>\n\n    <h4>Lens</h4>\n\n    <LabeledInput :formstate=\"formstate\" :name=\"`${namePrefix}-physical-lens-name`\" label=\"Lens name\">\n      <PropertyInputText\n        v-model=\"localPhysical.lens.name\"\n        :name=\"`${namePrefix}-physical-lens-name`\"\n        :schema-property=\"physicalLensProperties.name\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`${namePrefix}-physical-lens-degreesMinMax`\"\n      label=\"Beam angle\">\n      <PropertyInputRange\n        v-model=\"localPhysical.lens.degreesMinMax\"\n        :name=\"`${namePrefix}-physical-lens-degreesMinMax`\"\n        :schema-property=\"physicalLensProperties.degreesMinMax\"\n        :formstate=\"formstate\"\n        start-hint=\"min\"\n        end-hint=\"max\"\n        unit=\"°\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp, stringProp } from 'vue-ts-types';\nimport {\n  physicalBulbProperties,\n  physicalLensProperties,\n  physicalProperties,\n  schemaDefinitions,\n} from '../../../lib/schema-properties.js';\nimport LabeledInput from '../LabeledInput.vue';\nimport PropertyInputDimensions from '../PropertyInputDimensions.vue';\nimport PropertyInputNumber from '../PropertyInputNumber.vue';\nimport PropertyInputRange from '../PropertyInputRange.vue';\nimport PropertyInputSelect from '../PropertyInputSelect.vue';\nimport PropertyInputText from '../PropertyInputText.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputDimensions,\n    PropertyInputNumber,\n    PropertyInputRange,\n    PropertyInputSelect,\n    PropertyInputText,\n  },\n  model: {\n    prop: 'model-value',\n    event: 'update:model-value',\n  },\n  props: {\n    modelValue: objectProp().required,\n    formstate: objectProp().required,\n    namePrefix: stringProp().required,\n  },\n  emits: {\n    'update:model-value': (value) => true,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      physicalProperties,\n      physicalBulbProperties,\n      physicalLensProperties,\n      localPhysical: structuredClone(this.modelValue),\n    };\n  },\n  watch: {\n    localPhysical: {\n      handler() {\n        this.$emit('update:model-value', structuredClone(this.localPhysical));\n      },\n      deep: true,\n    },\n    async 'modelValue.DMXconnector'(newValue) {\n      if (newValue === '[add-value]' && this.$root._oflRestoreComplete) {\n        await this.$nextTick();\n        this.$refs.newDmxConnectorInput.focus();\n      }\n    },\n  },\n  mounted() {\n    if (this.$root._oflRestoreComplete) {\n      this.$refs.firstInput.focus();\n    }\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorProportionalPropertySwitcher.vue",
    "content": "<template>\n  <div class=\"proportional-capability-data\">\n\n    <Component\n      :is=\"formstate ? 'Validate' : 'span'\"\n      v-if=\"hasStartEnd\"\n      :state=\"formstate\"\n      :tag=\"formstate ? 'span' : null\">\n\n      <Component\n        :is=\"formstate ? 'Validate' : 'label'\"\n        :state=\"formstate\"\n        :tag=\"formstate ? 'label' : null\"\n        class=\"entity-input\">\n\n        <PropertyInputNumber\n          v-if=\"entity === `slotNumber`\"\n          ref=\"startField\"\n          v-model=\"slotNumberStart\"\n          :name=\"`capability${capability.uuid}-${propertyName}Start`\"\n          :required=\"required\"\n          :schema-property=\"slotNumberSchema\"\n          :step-override=\"0.5\" />\n\n        <PropertyInputEntity\n          v-else-if=\"entitySchema\"\n          ref=\"startField\"\n          v-model=\"propertyDataStart\"\n          :name=\"`capability${capability.uuid}-${propertyName}Start`\"\n          :required=\"required\"\n          :schema-property=\"entitySchema\"\n          :associated-entity=\"propertyDataEnd\"\n          @unit-selected=\"onUnitSelected($event)\" />\n\n        <PropertyInputText\n          v-else\n          ref=\"startField\"\n          v-model=\"propertyDataStart\"\n          :name=\"`capability${capability.uuid}-${propertyName}Start`\"\n          :required=\"required\"\n          :schema-property=\"schemaDefinitions.nonEmptyString\"\n          :valid-color-hex-list=\"propertyName === `colorsHexString`\"\n          hint=\"start\" />\n\n        <span class=\"hint\">\n          {{ hint || `value` }} at\n          {{ capability.dmxRange && capability.dmxRange[0] !== null ? `DMX value ${capability.dmxRange[0]}` : `capability start` }}\n        </span>\n\n      </Component>\n\n      <span class=\"separator\">\n        <button\n          :tabindex=\"swapButtonTabIndex\"\n          type=\"button\"\n          class=\"swap icon-button\"\n          title=\"Swap start and end values\"\n          @click.prevent=\"swapStartEnd()\">\n          <OflSvg name=\"swap-horizontal\" />\n        </button>\n        …\n      </span>\n\n      <Component\n        :is=\"formstate ? 'Validate' : 'label'\"\n        :state=\"formstate\"\n        :tag=\"formstate ? 'label' : null\"\n        class=\"entity-input\">\n\n        <PropertyInputNumber\n          v-if=\"entity === `slotNumber`\"\n          ref=\"endField\"\n          v-model=\"slotNumberEnd\"\n          :name=\"`capability${capability.uuid}-${propertyName}End`\"\n          :required=\"required\"\n          :schema-property=\"slotNumberSchema\"\n          :step-override=\"0.5\" />\n\n        <PropertyInputEntity\n          v-else-if=\"entitySchema\"\n          ref=\"endField\"\n          v-model=\"propertyDataEnd\"\n          :name=\"`capability${capability.uuid}-${propertyName}End`\"\n          :required=\"required\"\n          :schema-property=\"entitySchema\"\n          :associated-entity=\"propertyDataStart\"\n          @unit-selected=\"onUnitSelected($event)\" />\n\n        <PropertyInputText\n          v-else\n          ref=\"endField\"\n          v-model=\"propertyDataEnd\"\n          :name=\"`capability${capability.uuid}-${propertyName}End`\"\n          :required=\"required\"\n          :schema-property=\"schemaDefinitions.nonEmptyString\"\n          :valid-color-hex-list=\"propertyName === `colorsHexString`\"\n          hint=\"end\" />\n\n        <span class=\"hint\">\n          {{ hint || `value` }} at\n          {{ capability.dmxRange && capability.dmxRange[1] !== null ? `DMX value ${capability.dmxRange[1]}` : `capability end` }}\n        </span>\n\n      </Component>\n    </Component>\n\n    <template v-else>\n      <PropertyInputNumber\n        v-if=\"entity === `slotNumber`\"\n        ref=\"steppedField\"\n        v-model=\"slotNumberStepped\"\n        :name=\"`capability${capability.uuid}-${propertyName}`\"\n        :required=\"required\"\n        :schema-property=\"slotNumberSchema\"\n        :step-override=\"0.5\" />\n\n      <PropertyInputEntity\n        v-else-if=\"entitySchema\"\n        ref=\"steppedField\"\n        v-model=\"propertyDataStepped\"\n        :name=\"`capability${capability.uuid}-${propertyName}`\"\n        :required=\"required\"\n        :schema-property=\"entitySchema\" />\n\n      <PropertyInputText\n        v-else\n        ref=\"steppedField\"\n        v-model=\"propertyDataStepped\"\n        :name=\"`capability${capability.uuid}-${propertyName}`\"\n        :required=\"required\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\"\n        :valid-color-hex-list=\"propertyName === `colorsHexString`\" />\n\n      <span v-if=\"hint\" class=\"hint\">{{ hint }}</span>\n    </template>\n\n    <section>\n      <label>\n        <input v-model=\"hasStartEnd\" type=\"checkbox\" @change=\"focusEndField()\">\n        Specify range instead of a single value\n      </label>\n    </section>\n\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.entity-input {\n  display: inline-block;\n  vertical-align: top;\n}\n\n.separator {\n  position: relative;\n  margin: 0 1ex;\n  vertical-align: -8px;\n\n  .icon-button.swap {\n    position: absolute;\n    bottom: 0;\n    left: 50%;\n    margin-left: -1rem;\n    background: none;\n    border: none;\n  }\n}\n\n.proportional-capability-data {\n  & .icon-button.swap {\n    opacity: 0;\n    transition-property: opacity, fill;\n  }\n\n  &:hover .icon-button.swap,\n  & .icon-button.swap:focus {\n    opacity: 1;\n  }\n\n  &:focus-within .icon-button.swap {\n    opacity: 1;\n  }\n}\n</style>\n\n<script>\nimport { booleanProp, objectProp, stringProp } from 'vue-ts-types';\nimport {\n  capabilityTypes,\n  entitiesSchema,\n  schemaDefinitions,\n  unitsSchema,\n} from '../../../lib/schema-properties.js';\nimport PropertyInputEntity from '../PropertyInputEntity.vue';\nimport PropertyInputNumber from '../PropertyInputNumber.vue';\nimport PropertyInputText from '../PropertyInputText.vue';\n\nexport default {\n  components: {\n    PropertyInputEntity,\n    PropertyInputNumber,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    propertyName: stringProp().required,\n    required: booleanProp().withDefault(false),\n    hint: stringProp().optional,\n    formstate: objectProp().optional,\n  },\n  data() {\n    const slotNumberUnit = entitiesSchema.slotNumber.$ref.replace('#/units/', '');\n\n    return {\n      schemaDefinitions,\n      slotNumberSchema: unitsSchema[slotNumberUnit],\n    };\n  },\n  computed: {\n    entity() {\n      const capabilitySchema = capabilityTypes[this.capability.type];\n      if (!capabilitySchema) {\n        return '';\n      }\n\n      const propertySchema = capabilitySchema.properties[this.propertyName];\n      if (!propertySchema) {\n        return '';\n      }\n\n      return (propertySchema.$ref || '').replace('definitions.json#/entities/', '');\n    },\n    entitySchema() {\n      if (this.entity === '') {\n        return null;\n      }\n\n      return entitiesSchema[this.entity];\n    },\n    propertyDataStepped: {\n      get() {\n        return this.capability.typeData[this.propertyName];\n      },\n      set(newData) {\n        this.capability.typeData[this.propertyName] = newData;\n      },\n    },\n    propertyDataStart: {\n      get() {\n        return this.capability.typeData[`${this.propertyName}Start`];\n      },\n      set(newData) {\n        this.capability.typeData[`${this.propertyName}Start`] = newData;\n      },\n    },\n    propertyDataEnd: {\n      get() {\n        return this.capability.typeData[`${this.propertyName}End`];\n      },\n      set(newData) {\n        this.capability.typeData[`${this.propertyName}End`] = newData;\n      },\n    },\n    hasStartEnd: {\n      get() {\n        if (this.propertyDataStepped === null && this.propertyDataStart === null) {\n          throw new Error('Stepped and start value are both null. At least one of them should have a value, e.g. an empty string.');\n        }\n\n        return this.propertyDataStepped === null;\n      },\n      set(shouldHaveStartEnd) {\n        if (shouldHaveStartEnd && !this.hasStartEnd) {\n          const savedData = this.propertyDataStepped;\n          this.propertyDataStepped = null;\n          this.propertyDataStart = savedData;\n          this.propertyDataEnd = savedData;\n        }\n        else if (!shouldHaveStartEnd && this.hasStartEnd) {\n          const savedData = this.propertyDataStart;\n          this.propertyDataStepped = savedData;\n          this.propertyDataStart = null;\n          this.propertyDataEnd = null;\n        }\n      },\n    },\n\n    // slotNumber entity requires a bit of special handling\n    slotNumberStepped: {\n      get() {\n        return this.capability.typeData[this.propertyName];\n      },\n      set(newData) {\n        this.capability.typeData[this.propertyName] = newData === null ? '' : newData;\n      },\n    },\n    slotNumberStart: {\n      get() {\n        return this.capability.typeData[`${this.propertyName}Start`];\n      },\n      set(newData) {\n        this.capability.typeData[`${this.propertyName}Start`] = newData === null ? '' : newData;\n      },\n    },\n    slotNumberEnd: {\n      get() {\n        return this.capability.typeData[`${this.propertyName}End`];\n      },\n      set(newData) {\n        this.capability.typeData[`${this.propertyName}End`] = newData === null ? '' : newData;\n      },\n    },\n\n    swapButtonTabIndex() {\n      return (\n        (\n          this.propertyDataStart === this.propertyDataEnd\n          || this.propertyDataStart === ''\n          || this.propertyDataEnd === ''\n        )\n          ? '-1'\n          : null\n      );\n    },\n  },\n  methods: {\n    /** @public */\n    focus() {\n      for (const field of ['steppedField', 'startField', 'endField']) {\n        if (this.$refs[field]) {\n          this.$refs[field].focus();\n          return;\n        }\n      }\n    },\n    async focusEndField() {\n      await this.$nextTick();\n\n      if (this.hasStartEnd) {\n        const focusField = this.propertyDataStart === '' ? this.$refs.startField : this.$refs.endField;\n        focusField.focus();\n      }\n    },\n    onUnitSelected(newUnit) {\n      if (!this.propertyDataStart.endsWith(newUnit)) {\n        this.$refs.startField.setUnitString(newUnit);\n      }\n      if (!this.propertyDataEnd.endsWith(newUnit)) {\n        this.$refs.endField.setUnitString(newUnit);\n      }\n    },\n    swapStartEnd() {\n      [this.propertyDataStart, this.propertyDataEnd] = [this.propertyDataEnd, this.propertyDataStart];\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorRestoreDialog.vue",
    "content": "<template>\n  <A11yDialog\n    id=\"restore-dialog\"\n    is-alert-dialog\n    :shown=\"modelValue !== undefined\"\n    title=\"Auto-saved fixture data found\">\n\n    Do you want to restore the data (auto-saved <time>{{ restoredDate }}</time>) to continue to create the fixture?\n\n    <div class=\"button-bar right\">\n      <button\n        type=\"submit\"\n        class=\"discard secondary\"\n        @click.prevent=\"discardRestored()\">\n        Discard data\n      </button>\n      <button\n        type=\"submit\"\n        class=\"restore primary\"\n        @click.prevent=\"applyRestored()\">\n        Restore to continue work\n      </button>\n    </div>\n\n  </A11yDialog>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport {\n  getEmptyCapability,\n  getEmptyChannel,\n  getEmptyFineChannel,\n  getEmptyFixture,\n  getEmptyLink,\n  getEmptyMode,\n  getEmptyPhysical,\n  getSanitizedChannel,\n} from '../../assets/scripts/editor-utilities.js';\nimport A11yDialog from '../A11yDialog.vue';\n\nexport default {\n  components: {\n    A11yDialog,\n  },\n  model: {\n    prop: 'model-value',\n    event: 'update:model-value',\n  },\n  props: {\n    modelValue: objectProp().optional,\n  },\n  emits: {\n    'update:model-value': (value) => true,\n    'restore-complete': () => true,\n  },\n  computed: {\n    restoredDate() {\n      if (this.modelValue === undefined) {\n        return undefined;\n      }\n      return (new Date(this.modelValue.timestamp)).toISOString().replace(/\\..*$/, '').replace('T', ', ');\n    },\n  },\n  methods: {\n    discardRestored() {\n      // put all items except the last one back\n      localStorage.setItem('autoSave', JSON.stringify(JSON.parse(localStorage.getItem('autoSave')).slice(0, -1)));\n\n      this.$emit('update:model-value', undefined);\n      this.$emit('restore-complete');\n    },\n\n    async applyRestored() {\n      const modelValue = structuredClone(this.modelValue);\n\n      // closes dialog\n      this.$emit('update:model-value', undefined);\n\n      // restoring could open another dialog -> wait for DOM being up-to-date\n      await this.$nextTick();\n\n      this.$parent.fixture = getRestoredFixture(modelValue.fixture);\n      this.$parent.channel = getRestoredChannel(modelValue.channel, true);\n\n      await this.$nextTick();\n      this.$emit('restore-complete');\n    },\n  },\n};\n\n/**\n * @param {object} fixture The fixture object from the saved user data.\n * @returns {object} A fixture editor fixture object with all required properties.\n */\nfunction getRestoredFixture(fixture) {\n  const restoredFixture = Object.assign(getEmptyFixture(), fixture);\n\n  for (const [index, link] of restoredFixture.links.entries()) {\n    restoredFixture.links[index] = Object.assign(getEmptyLink(), link);\n  }\n\n  restoredFixture.physical = Object.assign(getEmptyPhysical(), restoredFixture.physical);\n\n  for (const [index, mode] of restoredFixture.modes.entries()) {\n    restoredFixture.modes[index] = Object.assign(getEmptyMode(), mode);\n    restoredFixture.modes[index].physical = Object.assign(getEmptyPhysical(), mode.physical);\n  }\n\n  for (const channelKey of Object.keys(restoredFixture.availableChannels)) {\n    restoredFixture.availableChannels[channelKey] = getRestoredChannel(restoredFixture.availableChannels[channelKey], false);\n  }\n\n  return restoredFixture;\n}\n\n/**\n * @param {object} channel The channel object from the saved user data.\n * @param {booelan} isChannelDialog True if the channel object is used in the channel dialog and should therefore not be sanitized.\n * @returns {object} A fixture editor channel object with all required properties.\n */\nfunction getRestoredChannel(channel, isChannelDialog) {\n  if ('coarseChannelId' in channel) {\n    return Object.assign(getEmptyFineChannel(), channel);\n  }\n\n  let emptyChannel = getEmptyChannel();\n  if (!isChannelDialog) {\n    emptyChannel = getSanitizedChannel(emptyChannel);\n  }\n\n  const restoredChannel = Object.assign(emptyChannel, channel);\n\n  for (const [index, capability] of restoredChannel.capabilities.entries()) {\n    restoredChannel.capabilities[index] = Object.assign(\n      getEmptyCapability(),\n      capability,\n    );\n  }\n\n  if (isChannelDialog) {\n    restoredChannel.wizard.templateCapability = Object.assign(\n      getEmptyCapability(),\n      restoredChannel.wizard.templateCapability,\n    );\n  }\n\n  return restoredChannel;\n}\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorSubmitDialog.vue",
    "content": "<template>\n  <A11yDialog\n    id=\"submit-dialog\"\n    is-alert-dialog\n    :shown=\"state !== `closed`\"\n    :title=\"title\"\n    :wide=\"state === `preview`\">\n\n    <template v-if=\"state === `preview`\" #title>\n      <span class=\"preview-fixture-title\">{{ title }}</span>\n      <select\n        v-if=\"fixtureKeys.length > 1\"\n        v-model=\"previewFixtureKey\"\n        class=\"preview-fixture-chooser\">\n        <option disabled>Choose fixture to preview</option>\n        <option\n          v-for=\"key of fixtureKeys\"\n          :key=\"key\"\n          :value=\"key\">{{ key }}</option>\n      </select>\n    </template>\n\n    <div v-if=\"state === `validating`\">Validating…</div>\n\n    <div v-else-if=\"state === `ready`\">\n      <template v-if=\"!hasPreview\">\n        Unfortunately, the fixture validation returned some issues.\n        Due to some of those, there is also no preview available.\n        You can try to resolve as many errors as you can (some may be unavoidable in the editor)\n        and then submit your fixture{{ isPlural ? `s` : `` }} to the Open Fixture Library project.\n        After submitting, we will review the fixture{{ isPlural ? `s` : `` }} and fix all remaining issues.\n      </template>\n      <template v-else-if=\"hasValidationErrors || hasValidationWarnings\">\n        Unfortunately, the fixture validation returned some issues.\n        You can try to resolve as many as you can (some may be unavoidable in the editor).\n        Next, head over to the preview, where it is also possible to download\n        your current fixture{{ isPlural ? `s` : `` }} for private use.\n        After that, please submit your fixture{{ isPlural ? `s` : `` }} to the Open Fixture Library project,\n        where {{ isPlural ? `they` : `it` }} will be reviewed and added to the library.\n      </template>\n      <template v-else>\n        Your fixture validation was successful.\n        Next, head over to the preview, where it is also possible to download\n        your current fixture{{ isPlural ? `s` : `` }} for private use.\n        After that, please submit your fixture{{ isPlural ? `s` : `` }} to the Open Fixture Library project,\n        where {{ isPlural ? `they` : `it` }} will be reviewed and added to the library.\n      </template>\n\n      <ul>\n        <li v-for=\"key of fixtureKeys\" :key=\"key\">\n          <strong>{{ key }}</strong>\n          <ul>\n            <li v-for=\"message of fixtureCreateResult.errors[key]\" :key=\"message\">\n              Error: {{ message }}\n            </li>\n            <li v-for=\"message of fixtureCreateResult.warnings[key]\" :key=\"message\">\n              {{ message }}\n            </li>\n          </ul>\n        </li>\n      </ul>\n\n      <div class=\"button-bar right\">\n        <button type=\"button\" class=\"secondary\" @click.prevent=\"onCancel()\">Continue editing</button>\n        <button\n          v-if=\"hasPreview\"\n          type=\"button\"\n          class=\"primary\"\n          @click.prevent=\"onPreview()\">Preview fixture{{ isPlural ? `s` : `` }}</button>\n        <button\n          v-else\n          type=\"button\"\n          class=\"primary\"\n          @click.prevent=\"onSubmit()\">Submit to OFL</button>\n      </div>\n    </div>\n\n    <div v-else-if=\"state === `preview`\">\n      <div v-if=\"previewFixture\" class=\"fixture-page\">\n        <FixtureHeader>\n          <template #title>\n            <h1>\n              {{ previewFixture.manufacturer.name }} {{ previewFixture.name }}\n              <code v-if=\"previewFixture.hasShortName\">{{ previewFixture.shortName }}</code>\n            </h1>\n          </template>\n\n          <DownloadButton\n            v-if=\"previewFixtureResults.errors.length === 0\"\n            :editor-fixtures=\"previewFixtureCreateResult\" />\n        </FixtureHeader>\n\n        <section v-if=\"previewFixtureResults.warnings.length > 0\" class=\"card yellow\">\n          <strong>Warnings:<br></strong>\n          <span v-for=\"message of previewFixtureResults.warnings\" :key=\"message\">\n            {{ message }}<br>\n          </span>\n        </section>\n\n        <section v-if=\"previewFixtureResults.errors.length > 0\" class=\"card red\">\n          <strong>Errors (prevent showing the fixture preview):<br></strong>\n          <span v-for=\"message of previewFixtureResults.errors\" :key=\"message\">\n            {{ message }}<br>\n          </span>\n        </section>\n\n        <FixturePage\n          v-if=\"previewFixtureResults.errors.length === 0\"\n          :fixture=\"previewFixture\" />\n      </div>\n\n      <div class=\"button-bar right\">\n        <button type=\"button\" class=\"secondary\" @click.prevent=\"onCancel()\">Continue editing</button>\n        <button type=\"button\" class=\"primary\" @click.prevent=\"onSubmit()\">Submit to OFL</button>\n      </div>\n    </div>\n\n    <div v-else-if=\"state === `uploading`\">Uploading…</div>\n\n    <div v-else-if=\"state === `success`\">\n      Your fixture was successfully uploaded to GitHub (see the\n      <a :href=\"pullRequestUrl\" target=\"_blank\" rel=\"noopener\">pull request</a>).\n      It will be now reviewed and then published on the website (this may take a few days).\n      Thank you for your contribution!\n\n      <div class=\"button-bar right\">\n        <NuxtLink to=\"/\" class=\"button secondary\">Back to homepage</NuxtLink>\n        <button type=\"button\" class=\"button secondary\" @click.prevent=\"onReset()\">Close</button>\n        <DownloadButton\n          v-if=\"!hasValidationErrors\"\n          button-style=\"select\"\n          :editor-fixtures=\"fixtureCreateResult\" />\n        <a\n          :href=\"pullRequestUrl\"\n          class=\"button primary\"\n          target=\"_blank\"\n          rel=\"noopener\">\n          See pull request\n        </a>\n      </div>\n    </div>\n\n    <div v-else-if=\"state === `error`\">\n      Unfortunately, there was an error while uploading. Please copy the following data and\n      <a\n        href=\"https://github.com/OpenLightingProject/open-fixture-library/issues/new\"\n        target=\"_blank\"\n        rel=\"noopener\">\n        manually submit them to GitHub\n      </a>.\n\n      <textarea v-model=\"rawData\" readonly />\n\n      <div class=\"button-bar right\">\n        <button type=\"button\" class=\"button secondary\" @click.prevent=\"onCancel()\">Close</button>\n        <a\n          href=\"https://github.com/OpenLightingProject/open-fixture-library/issues/new\"\n          class=\"button primary\"\n          target=\"_blank\"\n          rel=\"noopener\">\n          Submit manually\n        </a>\n      </div>\n    </div>\n\n  </A11yDialog>\n</template>\n\n<style lang=\"scss\" scoped>\n.preview-fixture-title {\n  margin-right: 1ex;\n}\n\n.preview-fixture-chooser {\n  width: 350px;\n  font-size: 1rem;\n  vertical-align: middle;\n}\n\n.fixture-page {\n  padding: 0.1rem 1rem 1rem;\n  margin: 1rem -1rem -1rem;\n  background: theme-color(page-background);\n\n  & ::v-deep .help-wanted .actions {\n    cursor: not-allowed;\n\n    a {\n      pointer-events: none;\n      opacity: 0.7;\n    }\n  }\n}\n\n.button-bar {\n  position: sticky;\n  bottom: 0;\n  padding: 0.6rem 1rem 1rem;\n  margin: 1rem -1rem -1rem;\n  background: theme-color(dialog-background);\n  box-shadow: 0 0 4px theme-color(icon-inactive);\n}\n</style>\n\n<script>\nimport { stringProp } from 'vue-ts-types';\nimport Fixture from '../../../lib/model/Fixture.js';\nimport Manufacturer from '../../../lib/model/Manufacturer.js';\nimport A11yDialog from '../A11yDialog.vue';\nimport DownloadButton from '../DownloadButton.vue';\nimport FixturePage from '../fixture-page/FixturePage.vue';\nimport FixtureHeader from '../FixtureHeader.vue';\n\nconst stateTitles = {\n  closed: 'Closed',\n  validating: 'Validating your new fixture…',\n  ready: 'Submit your new fixture',\n  preview: 'Preview fixture',\n  uploading: 'Submitting your new fixture…',\n  success: 'Upload complete',\n  error: 'Upload failed',\n};\nconst stateTitlesPlural = {\n  ready: 'Submit your new fixtures',\n  uploading: 'Submitting your new fixtures…',\n};\n\nexport default {\n  components: {\n    A11yDialog,\n    DownloadButton,\n    FixturePage,\n    FixtureHeader,\n  },\n  props: {\n    endpoint: stringProp().required,\n    githubUsername: stringProp().optional,\n    githubComment: stringProp().optional,\n  },\n  emits: {\n    success: () => true,\n    reset: () => true,\n  },\n  data() {\n    return {\n      state: 'closed',\n      requestBody: null,\n      error: null,\n      pullRequestUrl: null,\n      fixtureCreateResult: null,\n      previewFixtureKey: null,\n    };\n  },\n  computed: {\n    fixtureKeys() {\n      if (this.fixtureCreateResult === null) {\n        return [];\n      }\n\n      return Object.keys(this.fixtureCreateResult.fixtures);\n    },\n    isPlural() {\n      return this.fixtureKeys.length > 1;\n    },\n    title() {\n      if (this.state in stateTitlesPlural && this.isPlural) {\n        return stateTitlesPlural[this.state];\n      }\n      return stateTitles[this.state];\n    },\n    rawData() {\n      const rawData = JSON.stringify(this.requestBody, null, 2);\n\n      if (this.state === 'error') {\n        const backticks = '```';\n        return `${backticks}json\\n${rawData}\\n\\n${this.error}\\n${backticks}`;\n      }\n\n      return rawData;\n    },\n    hasPreview() {\n      if (this.fixtureCreateResult === null) {\n        return false;\n      }\n\n      return Object.values(this.fixtureCreateResult.errors).some(\n        (errors) => errors.length === 0,\n      );\n    },\n    hasValidationErrors() {\n      if (this.fixtureCreateResult === null) {\n        return false;\n      }\n\n      return Object.values(this.fixtureCreateResult.errors).flat().length > 0;\n    },\n    hasValidationWarnings() {\n      if (this.fixtureCreateResult === null) {\n        return false;\n      }\n\n      return Object.values(this.fixtureCreateResult.warnings).flat().length > 0;\n    },\n    previewFixture() {\n      if (this.previewFixtureKey === null) {\n        return null;\n      }\n\n      const [manufacturerKey, fixtureKey] = this.previewFixtureKey.split('/');\n\n      const manufacturer = new Manufacturer(manufacturerKey, this.fixtureCreateResult.manufacturers[manufacturerKey]);\n\n      return new Fixture(manufacturer, fixtureKey, this.fixtureCreateResult.fixtures[this.previewFixtureKey]);\n    },\n    previewFixtureResults() {\n      if (this.previewFixtureKey === null) {\n        return null;\n      }\n\n      return {\n        warnings: this.fixtureCreateResult.warnings[this.previewFixtureKey],\n        errors: this.fixtureCreateResult.errors[this.previewFixtureKey],\n      };\n    },\n    previewFixtureCreateResult() {\n      if (this.previewFixtureKey === null) {\n        return null;\n      }\n\n      return {\n        manufacturers: this.fixtureCreateResult.manufacturers,\n        fixtures: {\n          [this.previewFixtureKey]: this.fixtureCreateResult.fixtures[this.previewFixtureKey],\n        },\n        warnings: {\n          [this.previewFixtureKey]: this.previewFixtureResults.warnings,\n        },\n        errors: {\n          [this.previewFixtureKey]: this.previewFixtureResults.errors,\n        },\n      };\n    },\n  },\n  methods: {\n    /**\n     * Called from fixture editor to open the dialog.\n     * @public\n     * @param {object} requestBody The data to pass to the API endpoint.\n     */\n    async validate(requestBody) {\n      this.requestBody = requestBody;\n\n      console.log('validate', structuredClone(this.requestBody));\n\n      this.state = 'validating';\n      try {\n        const response = await this.$axios.post(\n          this.endpoint,\n          this.requestBody,\n        );\n\n        this.fixtureCreateResult = response.data;\n        this.state = 'ready';\n      }\n      catch (error) {\n        let errorMessage = error.message;\n        if (error.response && error.response.data.error) {\n          errorMessage = error.response.data.error;\n        }\n\n        console.error('There was a problem with the request:', errorMessage);\n\n        this.error = errorMessage;\n        this.state = 'error';\n      }\n    },\n    async onPreview() {\n      this.previewFixtureKey = Object.keys(this.fixtureCreateResult.fixtures)[0];\n      this.state = 'preview';\n    },\n    async onSubmit() {\n      this.requestBody = {\n        fixtureCreateResult: this.fixtureCreateResult,\n        githubUsername: this.githubUsername ?? null,\n        githubComment: this.githubComment ?? null,\n      };\n\n      console.log('submit', structuredClone(this.requestBody));\n\n      this.state = 'uploading';\n      try {\n        const response = await this.$axios.post(\n          '/api/v1/fixtures/submit',\n          this.requestBody,\n        );\n\n        this.pullRequestUrl = response.data.pullRequestUrl;\n        this.state = 'success';\n        this.$emit('success');\n      }\n      catch (error) {\n        let errorMessage = error.message;\n        if (error.response && error.response.data.error) {\n          errorMessage = error.response.data.error;\n        }\n\n        console.error('There was a problem with the request:', errorMessage);\n\n        this.error = errorMessage;\n        this.state = 'error';\n      }\n    },\n    onReset() {\n      this.state = 'closed';\n      this.$emit('reset');\n    },\n    onCancel() {\n      this.state = 'closed';\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorWheelSlot.vue",
    "content": "<template>\n  <ConditionalDetails class=\"editor-wheel-slot\" :open=\"open\">\n    <template #summary>Details for wheel slot {{ slotNumber }}</template>\n\n    <div class=\"wheel-slot-content\">\n      <LabeledInput\n        :formstate=\"formstate\"\n        :custom-validators=\"{\n          'animation-gobo-end-without-start': animationGoboEndAfterStart,\n          'must-be-animation-gobo-end': animationGoboEndValid,\n        }\"\n        :name=\"`wheel-slot${slot.uuid}-type`\"\n        label=\"Slot type\">\n        <!-- eslint-disable-next-line vuejs-accessibility/no-onchange -- @change is fine here, as the action is non-destructive -->\n        <select\n          v-model=\"slot.type\"\n          :class=\"{ empty: slot.type === `` }\"\n          :name=\"`wheel-slot${slot.uuid}-type`\"\n          required\n          @change=\"changeSlotType()\">\n\n          <option value=\"\" disabled>Please select a slot type</option>\n\n          <option\n            v-for=\"type of slotTypes\"\n            :key=\"type\"\n            :value=\"type\">{{ type }}</option>\n\n        </select>\n      </LabeledInput>\n\n      <Component\n        :is=\"`WheelSlot${slot.type}`\"\n        v-if=\"slot.type !== ``\"\n        ref=\"typeData\"\n        :wheel-slot=\"slot\"\n        :formstate=\"formstate\" />\n    </div>\n  </ConditionalDetails>\n</template>\n\n<style lang=\"scss\" scoped>\n.wheel-slot-content {\n  padding: 0 1.5rem;\n}\n</style>\n\n<script>\nimport { integerProp, objectProp } from 'vue-ts-types';\nimport { wheelSlotTypes } from '../../../lib/schema-properties.js';\nimport { getEmptyWheelSlot } from '../../assets/scripts/editor-utilities.js';\nimport ConditionalDetails from '../ConditionalDetails.vue';\nimport LabeledInput from '../LabeledInput.vue';\nimport WheelSlotAnimationGoboEnd from './wheel-slots/WheelSlotAnimationGoboEnd.vue';\nimport WheelSlotAnimationGoboStart from './wheel-slots/WheelSlotAnimationGoboStart.vue';\nimport WheelSlotClosed from './wheel-slots/WheelSlotClosed.vue';\nimport WheelSlotColor from './wheel-slots/WheelSlotColor.vue';\nimport WheelSlotFrost from './wheel-slots/WheelSlotFrost.vue';\nimport WheelSlotGobo from './wheel-slots/WheelSlotGobo.vue';\nimport WheelSlotIris from './wheel-slots/WheelSlotIris.vue';\nimport WheelSlotOpen from './wheel-slots/WheelSlotOpen.vue';\nimport WheelSlotPrism from './wheel-slots/WheelSlotPrism.vue';\n\nexport default {\n  components: {\n    ConditionalDetails,\n    LabeledInput,\n    WheelSlotAnimationGoboEnd,\n    WheelSlotAnimationGoboStart,\n    WheelSlotClosed,\n    WheelSlotColor,\n    WheelSlotFrost,\n    WheelSlotGobo,\n    WheelSlotIris,\n    WheelSlotOpen,\n    WheelSlotPrism,\n  },\n  props: {\n    channel: objectProp().required,\n    slotNumber: integerProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      slotTypes: Object.keys(wheelSlotTypes),\n      open: false,\n    };\n  },\n  computed: {\n    slot() {\n      return this.channel.wheel.slots[this.slotNumber - 1];\n    },\n    suggestedType() {\n      const previousSlot = this.channel.wheel.slots[this.slotNumber - 2];\n      if (previousSlot && previousSlot.type === 'AnimationGoboStart') {\n        return 'AnimationGoboEnd';\n      }\n\n      if (this.slotNumber === 1) {\n        return /\\banimation\\b/i.test(this.channel.name) ? 'AnimationGoboStart' : 'Open';\n      }\n\n      return this.slotTypes.find((type) => this.channel.name.toLowerCase().includes(type.toLowerCase())) || '';\n    },\n    animationGoboEndAfterStart() {\n      if (this.slot.type !== 'AnimationGoboEnd') {\n        return true;\n      }\n\n      if (this.slotNumber === 1) {\n        return false;\n      }\n\n      const previousSlot = this.channel.wheel.slots[this.slotNumber - 2];\n      return !previousSlot || previousSlot.type === 'AnimationGoboStart';\n    },\n    animationGoboEndValid() {\n      const previousSlot = this.channel.wheel.slots[this.slotNumber - 2];\n      return !previousSlot || previousSlot.type !== 'AnimationGoboStart' || this.slot.type === 'AnimationGoboEnd';\n    },\n  },\n  created() {\n    this.$watch('slotNumber', async (newSlotNumber) => {\n      if (!this.channel.wheel.slots[newSlotNumber - 1]) {\n        this.$set(this.channel.wheel.slots, newSlotNumber - 1, getEmptyWheelSlot());\n        this.open = true;\n\n        await this.$nextTick();\n        this.slot.type = this.suggestedType;\n      }\n    }, {\n      immediate: true,\n    });\n  },\n  methods: {\n    /**\n     * Add all properties to capability.typeData that are required by the current wheel slot type and are not yet in there.\n     */\n    async changeSlotType() {\n      await this.$nextTick();\n\n      const defaultData = this.$refs.typeData.defaultData;\n      for (const property of Object.keys(defaultData)) {\n        if (!(property in this.slot.typeData)) {\n          this.$set(this.slot.typeData, property, defaultData[property]);\n        }\n      }\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/EditorWheelSlots.vue",
    "content": "<template>\n  <div class=\"capability-wheel-slots\">\n    <EditorWheelSlot\n      v-for=\"slotNumber of slotDetailNumbers\"\n      :key=\"slotNumber\"\n      :channel=\"channel\"\n      :slot-number=\"slotNumber\"\n      :formstate=\"formstate\" />\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n::v-deep details:nth-last-of-type(1):not([open]) {\n  margin-bottom: 1rem;\n}\n</style>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport EditorWheelSlot from './EditorWheelSlot.vue';\n\nexport default {\n  components: {\n    EditorWheelSlot,\n  },\n  props: {\n    capability: objectProp().required,\n    channel: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  computed: {\n    slotDetailNumbers() {\n      const slotNumbers = [\n        this.capability.typeData.slotNumber,\n        this.capability.typeData.slotNumberStart,\n        this.capability.typeData.slotNumberEnd,\n      ].filter((slotNumber) => typeof slotNumber === 'number');\n\n      if (slotNumbers.length === 0) {\n        return [];\n      }\n\n      const min = Math.floor(Math.min(...slotNumbers));\n      const max = Math.ceil(Math.max(...slotNumbers));\n      const length = max - min + 1;\n\n      // array of integers from min to max: [min, min+1, …, max-1, max]\n      const slotNumbersInRange = Array.from({ length }, (item, index) => min + index).filter((slotNumber) => slotNumber >= 1);\n\n      if (slotNumbers.at(-1) < slotNumbers[0]) {\n        slotNumbersInRange.reverse();\n      }\n\n      return slotNumbersInRange;\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityBeamAngle.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-angle`\"\n      label=\"Angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"angle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        angle: null,\n        angleStart: 'narrow',\n        angleEnd: 'wide',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityBeamPosition.vue",
    "content": "<template>\n\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-horizontalAngle`\"\n      label=\"Horizontal angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        :required=\"isPropertyEmpty(`verticalAngle`)\"\n        property-name=\"horizontalAngle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-verticalAngle`\"\n      label=\"Vertical angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        :required=\"isPropertyEmpty(`horizontalAngle`)\"\n        property-name=\"verticalAngle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Only move the beam and not a visible physical part of the fixture. This is especially useful for lasers. Use Pan/Tilt for moving heads.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        horizontalAngle: null,\n        horizontalAngleStart: '',\n        horizontalAngleEnd: '',\n        verticalAngle: null,\n        verticalAngleStart: '',\n        verticalAngleEnd: '',\n        comment: '',\n      },\n    };\n  },\n  methods: {\n    isPropertyEmpty(property) {\n      const typeData = this.capability.typeData;\n      const isSteppedEmpty = typeData[property] === null || typeData[property] === '';\n      const isProportionalEmpty = typeData[`${property}Start`] === null || typeData[`${property}Start`] === '';\n\n      return isSteppedEmpty && isProportionalEmpty;\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityBladeInsertion.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-blade`\"\n      label=\"Blade\">\n      <PropertyInputEntity\n        v-model=\"capability.typeData.blade\"\n        :name=\"`capability${capability.uuid}-blade`\"\n        :schema-property=\"bladeSchema\"\n        required />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-insertion`\"\n      label=\"Insertion\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"insertion\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { capabilityTypes, schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputEntity from '../../PropertyInputEntity.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputEntity,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      bladeSchema: capabilityTypes.BladeInsertion.properties.blade,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        blade: '',\n        insertion: null,\n        insertionStart: 'out',\n        insertionEnd: 'in',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityBladeRotation.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-blade`\"\n      label=\"Blade\">\n      <PropertyInputEntity\n        v-model=\"capability.typeData.blade\"\n        :name=\"`capability${capability.uuid}-blade`\"\n        :schema-property=\"bladeSchema\"\n        required />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-angle`\"\n      label=\"Angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"angle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { capabilityTypes, schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputEntity from '../../PropertyInputEntity.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputEntity,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      bladeSchema: capabilityTypes.BladeInsertion.properties.blade,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        blade: '',\n        angle: null,\n        angleStart: '0deg',\n        angleEnd: '360deg',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityBladeSystemRotation.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-angle`\"\n      label=\"Angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"angle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        angle: null,\n        angleStart: '0deg',\n        angleEnd: '360deg',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityColorIntensity.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-color`\"\n      label=\"Color\">\n      <select\n        v-model=\"capability.typeData.color\"\n        :class=\"{ empty: capability.typeData.color === `` }\"\n        :name=\"`capability${capability.uuid}-color`\"\n        required>\n\n        <option value=\"\" disabled>Please select a color</option>\n        <option\n          v-for=\"color of colors\"\n          :key=\"color\"\n          :value=\"color\">{{ color }}</option>\n\n      </select>\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-brightness`\"\n      label=\"Brightness\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"brightness\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { capabilityTypes, schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      colors: capabilityTypes.ColorIntensity.properties.color.enum,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        color: '',\n        brightness: null,\n        brightnessStart: 'off',\n        brightnessEnd: 'bright',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityColorPreset.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Color preset name\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n    <LabeledInput\n      multiple-inputs\n      label=\"Color hex code(s)\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"colorsHexString\"\n        hint=\"comma-separated list of #rrggbb hex codes\" />\n    </LabeledInput>\n\n    <LabeledInput\n      v-if=\"colorPreview !== null\"\n      key=\"color-preview\"\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-colorsHexString`\"\n      label=\"Color preview\">\n      <OflSvg\n        v-for=\"color of colorPreview\"\n        :key=\"color\"\n        :colors=\"[color]\"\n        type=\"color-circle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      v-if=\"colorPreviewStart !== null || colorPreviewEnd !== null\"\n      key=\"color-preview-start-end\"\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-colorsHexString`\"\n      label=\"Color preview\">\n      <OflSvg\n        v-for=\"color of colorPreviewStart || []\"\n        :key=\"color\"\n        :colors=\"[color]\"\n        type=\"color-circle\" />\n      …\n      <OflSvg\n        v-for=\"color of colorPreviewEnd || []\"\n        :key=\"color\"\n        :colors=\"[color]\"\n        type=\"color-circle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-colorTemperature`\"\n      label=\"Color temperature\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"colorTemperature\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport { colorsHexStringToArray } from '../../../assets/scripts/editor-utilities.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'This capability enables a static predefined RGB/CMY color. Use WheelSlot for color wheel filters.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        comment: '',\n        colors: null,\n        colorsStart: null,\n        colorsEnd: null,\n        colorsHexString: '',\n        colorsHexStringStart: null,\n        colorsHexStringEnd: null,\n        colorTemperature: '',\n        colorTemperatureStart: null,\n        colorTemperatureEnd: null,\n      },\n      colorPreview: null,\n      colorPreviewStart: null,\n      colorPreviewEnd: null,\n    };\n  },\n  watch: {\n    'capability.typeData.colorsHexString': {\n      handler(hexString) {\n        this.capability.typeData.colors = colorsHexStringToArray(hexString);\n        this.colorPreview = this.capability.typeData.colors;\n      },\n      immediate: true,\n    },\n    'capability.typeData.colorsHexStringStart': {\n      handler(hexString) {\n        this.capability.typeData.colorsStart = colorsHexStringToArray(hexString);\n        this.colorPreviewStart = this.capability.typeData.colorsStart;\n      },\n      immediate: true,\n    },\n    'capability.typeData.colorsHexStringEnd': {\n      handler(hexString) {\n        this.capability.typeData.colorsEnd = colorsHexStringToArray(hexString);\n        this.colorPreviewEnd = this.capability.typeData.colorsEnd;\n      },\n      immediate: true,\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityColorTemperature.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-colorTemperature`\"\n      label=\"Color temperature\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"colorTemperature\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        colorTemperature: null,\n        colorTemperatureStart: '',\n        colorTemperatureEnd: '',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityEffect.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-${capability.typeData.effectNameOrPreset}`\">\n\n      <template #label>\n        <template v-if=\"capability.typeData.effectNameOrPreset === `effectName`\">\n          Effect name / <a\n            href=\"#effectPreset\"\n            class=\"button secondary inline\"\n            title=\"Choose effect preset instead of entering effect name manually\"\n            @click.prevent=\"changeEffectNameOrPreset(`effectPreset`)\">preset</a>\n        </template>\n        <template v-else>\n          Effect preset / <a\n            href=\"#effectName\"\n            class=\"button secondary inline\"\n            title=\"Specify effect name manually instead of choosing effect preset\"\n            @click.prevent=\"changeEffectNameOrPreset(`effectName`)\">name</a>\n        </template>\n      </template>\n\n      <PropertyInputText\n        v-if=\"capability.typeData.effectNameOrPreset === `effectName`\"\n        ref=\"effectNameOrPresetInput\"\n        v-model=\"capability.typeData.effectName\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-effectName`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\"\n        required />\n\n      <select\n        v-else\n        ref=\"effectNameOrPresetInput\"\n        v-model=\"capability.typeData.effectPreset\"\n        :class=\"{ empty: capability.typeData.effectPreset === `` }\"\n        :name=\"`capability${capability.uuid}-effectPreset`\"\n        required>\n\n        <option value=\"\" disabled>Please select an effect preset</option>\n        <option\n          v-for=\"effect of effectPresets\"\n          :key=\"effect\"\n          :value=\"effect\">{{ effect }}</option>\n\n      </select>\n\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-speed`\"\n      label=\"Speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"speed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-duration`\"\n      label=\"Duration\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"duration\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-parameter`\"\n      label=\"Parameter\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"parameter\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-soundControlled`\"\n      label=\"Sound-controlled?\">\n      <PropertyInputBoolean\n        v-model=\"capability.typeData.soundControlled\"\n        :name=\"`capability${capability.uuid}-soundControlled`\"\n        label=\"Effect is sound-controlled\" />\n    </LabeledInput>\n\n    <LabeledInput\n      v-if=\"capability.typeData.soundControlled\"\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-soundSensitivity`\"\n      label=\"Sound sensitivity\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"soundSensitivity\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputBoolean from '../../PropertyInputBoolean.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputBoolean,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      effectPresets: schemaDefinitions.effectPreset.enum,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        effectNameOrPreset: 'effectName',\n        effectName: '',\n        effectPreset: '',\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        duration: '',\n        durationStart: null,\n        durationEnd: null,\n        parameter: '',\n        parameterStart: null,\n        parameterEnd: null,\n        soundControlled: null,\n        soundSensitivity: '',\n        soundSensitivityStart: null,\n        soundSensitivityEnd: null,\n        comment: '',\n      },\n    };\n  },\n  computed: {\n    /**\n     * Called from {@link EditorCapabilityTypeData}\n     * @public\n     * @returns {string[]} Array of all props to reset to default data when capability is saved.\n     */\n    resetProperties() {\n      const resetProperties = [this.capability.typeData.effectNameOrPreset === 'effectName' ? 'effectPreset' : 'effectName'];\n\n      if (!this.capability.typeData.soundControlled) {\n        resetProperties.push('soundSensitivity', 'soundSensitivityStart', 'soundSensitivityEnd');\n      }\n\n      return resetProperties;\n    },\n  },\n  methods: {\n    async changeEffectNameOrPreset(newValue) {\n      this.capability.typeData.effectNameOrPreset = newValue;\n\n      await this.$nextTick();\n      this.$refs.effectNameOrPresetInput.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityEffectDuration.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-duration`\"\n      label=\"Duration\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"duration\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate an effect, only controls the duration of running effects.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        duration: null,\n        durationStart: 'short',\n        durationEnd: 'long',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityEffectParameter.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-parameter`\"\n      label=\"Parameter\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"parameter\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate an effect, only controls a generic parameter of running effects.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        parameter: null,\n        parameterStart: 'low',\n        parameterEnd: 'high',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityEffectSpeed.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-speed`\"\n      label=\"Speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"speed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate an effect, only controls the speed of running effects.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speed: null,\n        speedStart: 'slow',\n        speedEnd: 'fast',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityFocus.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-distance`\"\n      label=\"Distance\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"distance\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        distance: null,\n        distanceStart: 'near',\n        distanceEnd: 'far',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityFog.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-fogType`\"\n      label=\"Fog type\">\n      <select\n        v-model=\"capability.typeData.fogType\"\n        :class=\"{ empty: capability.typeData.fogType === `` }\"\n        :name=\"`capability${capability.uuid}-fogType`\"\n        required>\n\n        <option value=\"\" disabled>Please select a fog type</option>\n        <option\n          v-for=\"fogType of fogTypes\"\n          :key=\"fogType\"\n          :value=\"fogType\">{{ fogType }}</option>\n\n      </select>\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-fogOutput`\"\n      label=\"Fog output\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"fogOutput\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { capabilityTypes, schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      fogTypes: capabilityTypes.Fog.properties.fogType.enum,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        fogType: '',\n        fogOutput: '',\n        fogOutputStart: null,\n        fogOutputEnd: null,\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityFogOutput.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-fogOutput`\"\n      label=\"Fog output\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"fogOutput\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate fog, only controls the intensity of the fog output.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        fogOutput: null,\n        fogOutputStart: 'weak',\n        fogOutputEnd: 'strong',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityFogType.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-fogType`\"\n      label=\"Fog type\">\n      <select\n        v-model=\"capability.typeData.fogType\"\n        :class=\"{ empty: capability.typeData.fogType === `` }\"\n        :name=\"`capability${capability.uuid}-fogType`\"\n        required>\n\n        <option value=\"\" disabled>Please select a fog type</option>\n        <option\n          v-for=\"fogType of fogTypes\"\n          :key=\"fogType\"\n          :value=\"fogType\">{{ fogType }}</option>\n\n      </select>\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { capabilityTypes, schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      fogTypes: capabilityTypes.Fog.properties.fogType.enum,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate fog, only selects the fog type (Fog or Haze).',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        fogType: '',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityFrost.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-frostIntensity`\"\n      label=\"Frost intensity\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"frostIntensity\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        frostIntensity: null,\n        frostIntensityStart: 'off',\n        frostIntensityEnd: 'high',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityFrostEffect.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-effectName`\"\n      label=\"Effect name\">\n      <PropertyInputText\n        v-model=\"capability.typeData.effectName\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-effectName`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\"\n        required />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-speed`\"\n      label=\"Speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"speed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'This capability enables a non-static frost effect, e.g. pulse. Use the Frost type instead if a static frost intensity can be chosen.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        effectName: '',\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityGeneric.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityIntensity.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-brightness`\"\n      label=\"Brightness\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"brightness\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Master dimmer for the lamp\\'s brightness. Use ColorIntensity for individual color components (e.g. Red, Green, Blue).',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        brightness: null,\n        brightnessStart: 'off',\n        brightnessEnd: 'bright',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityIris.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-openPercent`\"\n      label=\"Degree of opening\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"openPercent\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        openPercent: null,\n        openPercentStart: 'open',\n        openPercentEnd: 'closed',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityIrisEffect.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-effectName`\"\n      label=\"Effect name\">\n      <PropertyInputText\n        v-model=\"capability.typeData.effectName\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-effectName`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\"\n        required />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-speed`\"\n      label=\"Speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"speed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'This capability enables a non-static iris effect, e.g. pulse. Use the Iris type instead if a static degree of opening can be chosen.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        effectName: '',\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityMaintenance.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-parameter`\"\n      label=\"Parameter\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"parameter\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-hold`\"\n      label=\"Hold\">\n      <PropertyInputEntity\n        v-model=\"capability.typeData.hold\"\n        :name=\"`capability${capability.uuid}-hold`\"\n        :schema-property=\"holdSchema\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { capabilityTypes, entitiesSchema, schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputEntity from '../../PropertyInputEntity.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputEntity,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    const holdPropertySchema = capabilityTypes.Maintenance.properties.hold;\n    const holdEntityName = holdPropertySchema.$ref.replace('definitions.json#/entities/', '');\n\n    return {\n      schemaDefinitions,\n      holdSchema: entitiesSchema[holdEntityName],\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        parameter: '',\n        parameterStart: null,\n        parameterEnd: null,\n        hold: '',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityNoFunction.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityPan.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-angle`\"\n      label=\"Angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"angle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        angle: null,\n        angleStart: 'deg',\n        angleEnd: 'deg',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityPanContinuous.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-speed`\"\n      label=\"Speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"speed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityPanTiltSpeed.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-${capability.typeData.speedOrDuration}`\">\n\n      <template #label>\n        <template v-if=\"capability.typeData.speedOrDuration === `duration`\">\n          Duration / <a\n            href=\"#speed\"\n            class=\"button secondary inline\"\n            title=\"Specify speed instead of duration\"\n            @click.prevent=\"changeSpeedOrDuration(`speed`)\">Speed</a>\n        </template>\n        <template v-else>\n          Speed / <a\n            href=\"#duration\"\n            class=\"button secondary inline\"\n            title=\"Specify duration instead of speed\"\n            @click.prevent=\"changeSpeedOrDuration(`duration`)\">Duration</a>\n        </template>\n      </template>\n\n      <EditorProportionalPropertySwitcher\n        v-if=\"capability.typeData.speedOrDuration\"\n        ref=\"speedOrDurationInput\"\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        :property-name=\"capability.typeData.speedOrDuration\"\n        required />\n\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speedOrDuration: 'speed',\n        speed: null,\n        speedStart: 'fast',\n        speedEnd: 'slow',\n        duration: '',\n        durationStart: null,\n        durationEnd: null,\n        comment: '',\n      },\n    };\n  },\n  computed: {\n    /**\n     * Called from {@link EditorCapabilityTypeData}\n     * @public\n     * @returns {string[]} Array of all props to reset to default data when capability is saved.\n     */\n    resetProperties() {\n      const resetProperty = this.capability.typeData.speedOrDuration === 'duration' ? 'speed' : 'duration';\n\n      return [resetProperty, `${resetProperty}Start`, `${resetProperty}End`];\n    },\n  },\n  methods: {\n    async changeSpeedOrDuration(newValue) {\n      this.capability.typeData.speedOrDuration = newValue;\n\n      await this.$nextTick();\n      this.$refs.speedOrDurationInput.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityPrism.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-${capability.typeData.speedOrAngle}`\">\n\n      <template #label>\n        <template v-if=\"capability.typeData.speedOrAngle === `speed`\">\n          Speed / <a\n            href=\"#anglr\"\n            class=\"button secondary inline\"\n            title=\"Specify angle instead of speed\"\n            @click.prevent=\"changeSpeedOrAngle(`angle`)\">Angle</a>\n        </template>\n        <template v-else>\n          Angle / <a\n            href=\"#speed\"\n            class=\"button secondary inline\"\n            title=\"Specify speed instead of angle\"\n            @click.prevent=\"changeSpeedOrAngle(`speed`)\">Speed</a>\n        </template>\n      </template>\n\n      <EditorProportionalPropertySwitcher\n        v-if=\"capability.typeData.speedOrAngle\"\n        ref=\"speedOrAngleInput\"\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        :property-name=\"capability.typeData.speedOrAngle\" />\n\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speedOrAngle: 'speed',\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        angle: '',\n        angleStart: null,\n        angleEnd: null,\n        comment: '',\n      },\n    };\n  },\n  computed: {\n    /**\n     * Called from {@link EditorCapabilityTypeData}\n     * @public\n     * @returns {string[]} Array of all props to reset to default data when capability is saved.\n     */\n    resetProperties() {\n      const resetProperty = this.capability.typeData.speedOrAngle === 'speed' ? 'angle' : 'speed';\n\n      return [resetProperty, `${resetProperty}Start`, `${resetProperty}End`];\n    },\n  },\n  methods: {\n    async changeSpeedOrAngle(newValue) {\n      this.capability.typeData.speedOrAngle = newValue;\n\n      await this.$nextTick();\n      this.$refs.speedOrAngleInput.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityPrismRotation.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-${capability.typeData.speedOrAngle}`\">\n\n      <template #label>\n        <template v-if=\"capability.typeData.speedOrAngle === `speed`\">\n          Speed / <a\n            href=\"#angle\"\n            class=\"button secondary inline\"\n            title=\"Specify angle instead of speed\"\n            @click.prevent=\"changeSpeedOrAngle(`angle`)\">Angle</a>\n        </template>\n        <template v-else>\n          Angle / <a\n            href=\"#speed\"\n            class=\"button secondary inline\"\n            title=\"Specify speed instead of angle\"\n            @click.prevent=\"changeSpeedOrAngle(`speed`)\">Speed</a>\n        </template>\n      </template>\n\n      <EditorProportionalPropertySwitcher\n        v-if=\"capability.typeData.speedOrAngle\"\n        ref=\"speedOrAngleInput\"\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        :property-name=\"capability.typeData.speedOrAngle\"\n        required />\n\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate the prism, only controls the prism rotation.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speedOrAngle: 'speed',\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        angle: '',\n        angleStart: null,\n        angleEnd: null,\n        comment: '',\n      },\n    };\n  },\n  computed: {\n    /**\n     * Called from {@link EditorCapabilityTypeData}\n     * @public\n     * @returns {string[]} Array of all props to reset to default data when capability is saved.\n     */\n    resetProperties() {\n      const resetProperty = this.capability.typeData.speedOrAngle === 'speed' ? 'angle' : 'speed';\n\n      return [resetProperty, `${resetProperty}Start`, `${resetProperty}End`];\n    },\n  },\n  methods: {\n    async changeSpeedOrAngle(newValue) {\n      this.capability.typeData.speedOrAngle = newValue;\n\n      await this.$nextTick();\n      this.$refs.speedOrAngleInput.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityRotation.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-${capability.typeData.speedOrAngle}`\">\n\n      <template #label>\n        <template v-if=\"capability.typeData.speedOrAngle === `speed`\">\n          Speed / <a\n            href=\"#angle\"\n            class=\"button secondary inline\"\n            title=\"Specify angle instead of speed\"\n            @click.prevent=\"changeSpeedOrAngle(`angle`)\">Angle</a>\n        </template>\n        <template v-else>\n          Angle / <a\n            href=\"#speed\"\n            class=\"button secondary inline\"\n            title=\"Specify speed instead of angle\"\n            @click.prevent=\"changeSpeedOrAngle(`speed`)\">Speed</a>\n        </template>\n      </template>\n\n      <EditorProportionalPropertySwitcher\n        v-if=\"capability.typeData.speedOrAngle\"\n        ref=\"speedOrAngleInput\"\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        :property-name=\"capability.typeData.speedOrAngle\"\n        required />\n\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Only use this if no other type is applicable. Note that some types like WheelSlot and Prism also allow setting a rotation angle / speed value.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speedOrAngle: 'speed',\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        angle: '',\n        angleStart: null,\n        angleEnd: null,\n        comment: '',\n      },\n    };\n  },\n  computed: {\n    /**\n     * Called from {@link EditorCapabilityTypeData}\n     * @public\n     * @returns {string[]} Array of all props to reset to default data when capability is saved.\n     */\n    resetProperties() {\n      const resetProperty = this.capability.typeData.speedOrAngle === 'speed' ? 'angle' : 'speed';\n\n      return [resetProperty, `${resetProperty}Start`, `${resetProperty}End`];\n    },\n  },\n  methods: {\n    async changeSpeedOrAngle(newValue) {\n      this.capability.typeData.speedOrAngle = newValue;\n\n      await this.$nextTick();\n      this.$refs.speedOrAngleInput.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityShutterStrobe.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-shutterEffect`\"\n      label=\"Shutter effect\">\n      <select\n        v-model=\"capability.typeData.shutterEffect\"\n        :class=\"{ empty: capability.typeData.shutterEffect === `` }\"\n        :name=\"`capability${capability.uuid}-shutterEffect`\"\n        required>\n\n        <option value=\"\" disabled>Please select a shutter effect</option>\n        <option\n          v-for=\"effect of shutterEffects\"\n          :key=\"effect\"\n          :value=\"effect\">{{ effect }}</option>\n\n      </select>\n    </LabeledInput>\n\n    <template v-if=\"isStrobeEffect\">\n      <LabeledInput\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-soundControlled`\"\n        label=\"Sound-controlled?\">\n        <PropertyInputBoolean\n          v-model=\"capability.typeData.soundControlled\"\n          :name=\"`capability${capability.uuid}-soundControlled`\"\n          label=\"Strobe is sound-controlled\" />\n      </LabeledInput>\n\n      <LabeledInput\n        :formstate=\"formstate\"\n        multiple-inputs\n        :name=\"`capability${capability.uuid}-speed`\"\n        label=\"Speed\">\n        <EditorProportionalPropertySwitcher\n          :capability=\"capability\"\n          :formstate=\"formstate\"\n          property-name=\"speed\"\n          entity=\"speed\" />\n      </LabeledInput>\n\n      <LabeledInput\n        :formstate=\"formstate\"\n        multiple-inputs\n        :name=\"`capability${capability.uuid}-duration`\"\n        label=\"Duration\">\n        <EditorProportionalPropertySwitcher\n          :capability=\"capability\"\n          :formstate=\"formstate\"\n          property-name=\"duration\" />\n      </LabeledInput>\n\n      <LabeledInput\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-randomTiming`\"\n        label=\"Random timing?\">\n        <PropertyInputBoolean\n          v-model=\"capability.typeData.randomTiming\"\n          :name=\"`capability${capability.uuid}-randomTiming`\"\n          :label=\"`Random ${strobeEffectName}`\" />\n      </LabeledInput>\n    </template>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { capabilityTypes, schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputBoolean from '../../PropertyInputBoolean.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputBoolean,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      shutterEffects: capabilityTypes.ShutterStrobe.properties.shutterEffect.enum,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        shutterEffect: '',\n        soundControlled: null,\n        speed: null,\n        speedStart: '',\n        speedEnd: '',\n        duration: '',\n        durationStart: null,\n        durationEnd: null,\n        randomTiming: null,\n        comment: '',\n      },\n    };\n  },\n  computed: {\n    isStrobeEffect() {\n      return !['', 'Open', 'Closed'].includes(this.capability.typeData.shutterEffect);\n    },\n    strobeEffectName() {\n      return this.capability.typeData.shutterEffect === 'Strobe'\n        ? 'Strobe'\n        : `${this.capability.typeData.shutterEffect} Strobe`;\n    },\n\n    /**\n     * Called from {@link EditorCapabilityTypeData}\n     * @public\n     * @returns {string[]} Array of all props to reset to default data when capability is saved.\n     */\n    resetProperties() {\n      if (!this.isStrobeEffect) {\n        return [\n          'soundControlled',\n          'speed',\n          'speedStart',\n          'speedEnd',\n          'duration',\n          'durationStart',\n          'durationEnd',\n          'randomTiming',\n        ];\n      }\n\n      return [];\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilitySoundSensitivity.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-soundSensitivity`\"\n      label=\"Sound sensitivity\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"soundSensitivity\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate sound controlled mode (use Effect for this), only controls the microphone sensitivity.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        soundSensitivity: null,\n        soundSensitivityStart: 'low',\n        soundSensitivityEnd: 'high',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilitySpeed.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-speed`\"\n      label=\"Speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"speed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Only use this if no other type is applicable. Note that some types like Effect, PanContinuous or Rotation also allow setting a speed value.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speed: null,\n        speedStart: 'slow',\n        speedEnd: 'fast',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityStrobeDuration.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-duration`\"\n      label=\"Duration\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"duration\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate strobe, only controls the strobe flash duration.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        duration: null,\n        durationStart: 'ms',\n        durationEnd: 'ms',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityStrobeSpeed.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-speed`\"\n      label=\"Speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"speed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Doesn\\'t activate strobe, only controls the strobe frequency when another channel is set to a ShutterStrobe capability with shutter effect \\'Strobe\\'.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speed: null,\n        speedStart: 'Hz',\n        speedEnd: 'Hz',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityTilt.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-angle`\"\n      label=\"Angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"angle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        angle: null,\n        angleStart: 'deg',\n        angleEnd: 'deg',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityTiltContinuous.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-speed`\"\n      label=\"Speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"speed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityTime.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-time`\"\n      label=\"Time\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"time\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        time: null,\n        timeStart: '',\n        timeEnd: '',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityWheelRotation.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-${capability.typeData.speedOrAngle}`\">\n\n      <template #label>\n        <template v-if=\"capability.typeData.speedOrAngle === `speed`\">\n          Speed / <a\n            href=\"#angle\"\n            class=\"button secondary inline\"\n            title=\"Specify angle instead of speed\"\n            @click.prevent=\"changeSpeedOrAngle(`angle`)\">Angle</a>\n        </template>\n        <template v-else>\n          Angle / <a\n            href=\"#speed\"\n            class=\"button secondary inline\"\n            title=\"Specify speed instead of angle\"\n            @click.prevent=\"changeSpeedOrAngle(`speed`)\">Speed</a>\n        </template>\n      </template>\n\n      <EditorProportionalPropertySwitcher\n        v-if=\"capability.typeData.speedOrAngle\"\n        ref=\"speedOrAngleInput\"\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        :property-name=\"capability.typeData.speedOrAngle\"\n        required />\n\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      hint: 'Rotation of the whole wheel (i.e. over all wheel slots). Use WheelSlotRotation if only the slot itself (e.g. a Gobo) rotates in this capability. If the fixture doesn\\'t have a physical color wheel, use Effect with ColorFade/ColorJump preset instead.',\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        speedOrAngle: 'speed',\n        speed: null,\n        speedStart: 'slow CW',\n        speedEnd: 'fast CW',\n        angle: null,\n        angleStart: '0deg',\n        angleEnd: '360deg',\n        comment: '',\n      },\n    };\n  },\n  computed: {\n    /**\n     * Called from {@link EditorCapabilityTypeData}\n     * @public\n     * @returns {string[]} Array of all props to reset to default data when capability is saved.\n     */\n    resetProperties() {\n      const resetProperty = this.capability.typeData.speedOrAngle === 'speed' ? 'angle' : 'speed';\n\n      return [resetProperty, `${resetProperty}Start`, `${resetProperty}End`];\n    },\n  },\n  methods: {\n    async changeSpeedOrAngle(newValue) {\n      this.capability.typeData.speedOrAngle = newValue;\n\n      await this.$nextTick();\n      this.$refs.speedOrAngleInput.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityWheelShake.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-slotNumber`\"\n      label=\"Slot number\"\n      hint=\"Leave the slot number empty if this capability doesn't select a wheel slot, but only activates wheel shaking for a WheelSlot capability in another channel. Use 1.5 to indicate a wheel position halfway between slots 1 and 2.\"\n      style=\"display: inline-block; margin-bottom: 12px;\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"slotNumber\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-shakeSpeed`\"\n      label=\"Shake speed\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"shakeSpeed\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-shakeAngle`\"\n      label=\"Shake angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"shakeAngle\" />\n    </LabeledInput>\n\n    <EditorWheelSlots\n      :channel=\"channel\"\n      :capability=\"capability\"\n      :formstate=\"formstate\" />\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\nimport EditorWheelSlots from '../EditorWheelSlots.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    EditorWheelSlots,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    channel: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        slotNumber: '',\n        slotNumberStart: null,\n        slotNumberEnd: null,\n        shakeSpeed: '',\n        shakeSpeedStart: null,\n        shakeSpeedEnd: null,\n        shakeAngle: '',\n        shakeAngleStart: null,\n        shakeAngleEnd: null,\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityWheelSlot.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-slotNumber`\"\n      label=\"Slot number\"\n      hint=\"Use 1.5 to indicate a wheel position halfway between slots 1 and 2.\"\n      style=\"display: inline-block; margin-bottom: 12px;\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"slotNumber\" />\n    </LabeledInput>\n\n    <EditorWheelSlots\n      :channel=\"channel\"\n      :capability=\"capability\"\n      :formstate=\"formstate\" />\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\nimport EditorWheelSlots from '../EditorWheelSlots.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    EditorWheelSlots,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    channel: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        slotNumber: '',\n        slotNumberStart: null,\n        slotNumberEnd: null,\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityWheelSlotRotation.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-slotNumber`\"\n      label=\"Slot number\"\n      hint=\"Leave the slot number empty if this capability doesn't select a wheel slot, but only activates wheel slot rotation for a WheelSlot capability in another channel. Use 1.5 to indicate a wheel position halfway between slots 1 and 2.\"\n      style=\"display: inline-block; margin-bottom: 12px;\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        property-name=\"slotNumber\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-${capability.typeData.speedOrAngle}`\">\n\n      <template #label>\n        <template v-if=\"capability.typeData.speedOrAngle === `speed`\">\n          Speed / <a\n            href=\"#angle\"\n            class=\"button secondary inline\"\n            title=\"Specify angle instead of speed\"\n            @click.prevent=\"changeSpeedOrAngle(`angle`)\">Angle</a>\n        </template>\n        <template v-else>\n          Angle / <a\n            href=\"#speed\"\n            class=\"button secondary inline\"\n            title=\"Specify speed instead of angle\"\n            @click.prevent=\"changeSpeedOrAngle(`speed`)\">Speed</a>\n        </template>\n      </template>\n\n      <EditorProportionalPropertySwitcher\n        v-if=\"capability.typeData.speedOrAngle\"\n        ref=\"speedOrAngleInput\"\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        :property-name=\"capability.typeData.speedOrAngle\"\n        required />\n\n    </LabeledInput>\n\n    <EditorWheelSlots\n      :channel=\"channel\"\n      :capability=\"capability\"\n      :formstate=\"formstate\" />\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\nimport EditorWheelSlots from '../EditorWheelSlots.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    EditorWheelSlots,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    channel: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        slotNumber: '',\n        slotNumberStart: null,\n        slotNumberEnd: null,\n        speedOrAngle: 'speed',\n        speed: '',\n        speedStart: null,\n        speedEnd: null,\n        angle: '',\n        angleStart: null,\n        angleEnd: null,\n        comment: '',\n      },\n    };\n  },\n  computed: {\n    /**\n     * Called from {@link EditorCapabilityTypeData}\n     * @public\n     * @returns {string[]} Array of all props to reset to default data when capability is saved.\n     */\n    resetProperties() {\n      const resetProperty = this.capability.typeData.speedOrAngle === 'speed' ? 'angle' : 'speed';\n\n      return [resetProperty, `${resetProperty}Start`, `${resetProperty}End`];\n    },\n  },\n  methods: {\n    async changeSpeedOrAngle(newValue) {\n      this.capability.typeData.speedOrAngle = newValue;\n\n      await this.$nextTick();\n      this.$refs.speedOrAngleInput.focus();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/capabilities/CapabilityZoom.vue",
    "content": "<template>\n  <div class=\"capability-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`capability${capability.uuid}-angle`\"\n      label=\"Angle\">\n      <EditorProportionalPropertySwitcher\n        :capability=\"capability\"\n        :formstate=\"formstate\"\n        required\n        property-name=\"angle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`capability${capability.uuid}-comment`\"\n      label=\"Comment\">\n      <PropertyInputText\n        v-model=\"capability.typeData.comment\"\n        :formstate=\"formstate\"\n        :name=\"`capability${capability.uuid}-comment`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\nimport EditorProportionalPropertySwitcher from '../EditorProportionalPropertySwitcher.vue';\n\nexport default {\n  components: {\n    EditorProportionalPropertySwitcher,\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    capability: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorCapabilityTypeData}\n       * @public\n       */\n      defaultData: {\n        angle: null,\n        angleStart: 'narrow',\n        angleEnd: 'wide',\n        comment: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotAnimationGoboEnd.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\" />\n</template>\n\n<script>\nexport default {\n  inheritAttrs: false,\n  data() {\n    return {\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {},\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotAnimationGoboStart.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`wheel-slot${wheelSlot.uuid}-name`\"\n      label=\"Animation gobo name\">\n      <PropertyInputText\n        v-model=\"wheelSlot.typeData.name\"\n        :formstate=\"formstate\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-name`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    wheelSlot: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {\n        name: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotClosed.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\" />\n</template>\n\n<script>\nexport default {\n  inheritAttrs: false,\n  data() {\n    return {\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {},\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotColor.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`wheel-slot${wheelSlot.uuid}-name`\"\n      label=\"Color name\">\n      <PropertyInputText\n        v-model=\"wheelSlot.typeData.name\"\n        :formstate=\"formstate\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-name`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n    <LabeledInput\n      label=\"Color hex code(s)\"\n      :formstate=\"formstate\"\n      :name=\"`wheel-slot${wheelSlot.uuid}-colorsHexString`\">\n      <PropertyInputText\n        v-model=\"wheelSlot.typeData.colorsHexString\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-colorsHexString`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\"\n        valid-color-hex-list />\n    </LabeledInput>\n\n    <LabeledInput v-if=\"colorPreview !== null\" label=\"Color preview\">\n      <OflSvg\n        v-for=\"color of colorPreview\"\n        :key=\"color\"\n        :colors=\"[color]\"\n        type=\"color-circle\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`wheel-slot${wheelSlot.uuid}-colorTemperature`\"\n      label=\"Color temperature\">\n      <PropertyInputEntity\n        v-model=\"wheelSlot.typeData.colorTemperature\"\n        :formstate=\"formstate\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-colorTemperature`\"\n        :schema-property=\"entitiesSchema.colorTemperature\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { entitiesSchema, schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport { colorsHexStringToArray } from '../../../assets/scripts/editor-utilities.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputEntity from '../../PropertyInputEntity.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputEntity,\n    PropertyInputText,\n  },\n  props: {\n    wheelSlot: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      entitiesSchema,\n\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {\n        name: '',\n        colors: null,\n        colorsHexString: '',\n        colorTemperature: '',\n      },\n      colorPreview: null,\n    };\n  },\n  watch: {\n    'wheelSlot.typeData.colorsHexString': {\n      handler(hexString) {\n        this.wheelSlot.typeData.colors = colorsHexStringToArray(hexString);\n        this.colorPreview = this.wheelSlot.typeData.colors;\n      },\n      immediate: true,\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotFrost.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`wheel-slot${wheelSlot.uuid}-frostIntensity`\"\n      label=\"Frost intensity\">\n      <PropertyInputEntity\n        v-model=\"wheelSlot.typeData.frostIntensity\"\n        :formstate=\"formstate\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-frostIntensity`\"\n        :schema-property=\"entitiesSchema.percent\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { entitiesSchema } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputEntity from '../../PropertyInputEntity.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputEntity,\n  },\n  props: {\n    wheelSlot: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      entitiesSchema,\n\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {\n        frostIntensity: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotGobo.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`wheel-slot${wheelSlot.uuid}-name`\"\n      label=\"Gobo name\">\n      <PropertyInputText\n        v-model=\"wheelSlot.typeData.name\"\n        :formstate=\"formstate\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-name`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputText,\n  },\n  props: {\n    wheelSlot: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {\n        name: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotIris.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      multiple-inputs\n      :name=\"`wheel-slot${wheelSlot.uuid}-openPercent`\"\n      label=\"Degree of opening\">\n      <PropertyInputEntity\n        v-model=\"wheelSlot.typeData.openPercent\"\n        :formstate=\"formstate\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-openPercent`\"\n        :schema-property=\"entitiesSchema.irisPercent\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { entitiesSchema } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputEntity from '../../PropertyInputEntity.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputEntity,\n  },\n  props: {\n    wheelSlot: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      entitiesSchema,\n\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {\n        openPercent: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotOpen.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\" />\n</template>\n\n<script>\nexport default {\n  inheritAttrs: false,\n  data() {\n    return {\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {},\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/editor/wheel-slots/WheelSlotPrism.vue",
    "content": "<template>\n  <div class=\"wheel-slot-type-data\">\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`wheel-slot${wheelSlot.uuid}-name`\"\n      label=\"Prism name\">\n      <PropertyInputText\n        v-model=\"wheelSlot.typeData.name\"\n        :formstate=\"formstate\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-name`\"\n        :schema-property=\"schemaDefinitions.nonEmptyString\" />\n    </LabeledInput>\n\n    <LabeledInput\n      :formstate=\"formstate\"\n      :name=\"`wheel-slot${wheelSlot.uuid}-facets`\"\n      label=\"Facets\">\n      <PropertyInputNumber\n        v-model=\"wheelSlot.typeData.facets\"\n        :formstate=\"formstate\"\n        :name=\"`wheel-slot${wheelSlot.uuid}-facets`\"\n        :schema-property=\"facetsSchema\" />\n    </LabeledInput>\n\n  </div>\n</template>\n\n<script>\nimport { objectProp } from 'vue-ts-types';\nimport { schemaDefinitions, wheelSlotTypes } from '../../../../lib/schema-properties.js';\nimport LabeledInput from '../../LabeledInput.vue';\nimport PropertyInputNumber from '../../PropertyInputNumber.vue';\nimport PropertyInputText from '../../PropertyInputText.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n    PropertyInputNumber,\n    PropertyInputText,\n  },\n  props: {\n    wheelSlot: objectProp().required,\n    formstate: objectProp().optional,\n  },\n  data() {\n    return {\n      schemaDefinitions,\n      facetsSchema: wheelSlotTypes.Prism.properties.facets,\n\n      /**\n       * Used in {@link EditorWheelSlot}\n       * @public\n       */\n      defaultData: {\n        name: '',\n        facets: '',\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/fixture-page/FixturePage.vue",
    "content": "<template>\n  <div>\n    <section :style=\"{ borderTopColor: manufacturerColor }\" class=\"fixture-info card\">\n\n      <LabeledValue\n        name=\"categories\"\n        label=\"Categories\">\n        <CategoryBadge\n          v-for=\"cat of fixture.categories\"\n          :key=\"cat\"\n          :category=\"cat\" />\n      </LabeledValue>\n\n      <LabeledValue\n        v-if=\"fixture.hasComment\"\n        key=\"comment\"\n        :value=\"fixture.comment\"\n        name=\"comment\"\n        label=\"Comment\" />\n\n      <section v-if=\"videos\" class=\"fixture-videos\">\n        <div v-for=\"video of videos\" :key=\"video.url\" class=\"fixture-video\">\n          <EmbettyVideo\n            :type=\"video.type\"\n            :video-id=\"video.videoId\"\n            :start-at=\"video.startAt\"\n            server-url=\"https://embetty.open-fixture-library.org\" />\n          <a\n            :href=\"video.url\"\n            target=\"_blank\"\n            rel=\"nofollow noopener\">\n            <OflSvg name=\"youtube\" />\n            Watch video at {{ video.displayType }}\n          </a>\n        </div>\n      </section>\n\n      <LabeledValue\n        v-if=\"links.length > 0\"\n        key=\"links\"\n        name=\"links\"\n        label=\"Relevant links\">\n        <ul class=\"fixture-links\">\n          <li v-for=\"link of links\" :key=\"`${link.type}-${link.url}`\" :class=\"`link-${link.type}`\">\n            <a\n              :href=\"link.url\"\n              :title=\"link.title\"\n              target=\"_blank\"\n              rel=\"nofollow noopener\">\n              <OflSvg :name=\"link.iconName\" />\n              {{ link.name }}\n              <span v-if=\"link.type !== `other`\" class=\"hostname\">({{ link.hostname }})</span>\n            </a>\n          </li>\n        </ul>\n      </LabeledValue>\n\n      <HelpWantedMessage\n        v-if=\"fixture.isHelpWanted\"\n        type=\"fixture\"\n        :context=\"fixture\"\n        @help-wanted-clicked=\"$emit(`help-wanted-clicked`, $event)\" />\n\n      <LabeledValue\n        v-if=\"fixture.rdm !== null\"\n        key=\"rdm\"\n        name=\"rdm\">\n        <template #label>\n          <abbr title=\"Remote Device Management\">RDM</abbr> data\n        </template>\n\n        {{ fixture.manufacturer.rdmId }} (0x{{ fixture.manufacturer.rdmId.toString(16) }}) /\n        {{ fixture.rdm.modelId }} (0x{{ fixture.rdm.modelId.toString(16) }}) /\n        {{ `softwareVersion` in fixture.rdm ? fixture.rdm.softwareVersion : `?` }} –\n        <a :href=\"`http://rdm.openlighting.org/model/display?manufacturer=${fixture.manufacturer.rdmId}&model=${fixture.rdm.modelId}`\" rel=\"nofollow\">\n          <OflSvg name=\"ola\" /> View in Open Lighting RDM database\n        </a>\n        <span class=\"hint\">manufacturer ID / model ID / software version</span>\n      </LabeledValue>\n\n      <template v-if=\"fixture.physical !== null\">\n        <h3 class=\"physical\">Physical data</h3>\n        <section class=\"physical\">\n          <FixturePagePhysical :physical=\"fixture.physical\" />\n        </section>\n      </template>\n\n      <template v-if=\"fixture.matrix !== null\">\n        <h3 class=\"matrix\">Matrix</h3>\n        <section class=\"matrix\">\n          <FixturePageMatrix :matrix=\"fixture.matrix\" :physical=\"fixture.physical\" />\n        </section>\n      </template>\n\n      <template v-if=\"fixture.wheels.length > 0\">\n        <h3 class=\"wheels\">Wheels</h3>\n        <section class=\"wheels\">\n          <FixturePageWheel v-for=\"wheel of fixture.wheels\" :key=\"wheel.name\" :wheel=\"wheel\" />\n        </section>\n      </template>\n\n    </section>\n\n    <section class=\"fixture-modes\">\n      <FixturePageMode\n        v-for=\"mode of modes\"\n        :key=\"mode.name\"\n        :mode=\"mode\"\n        @help-wanted-clicked=\"$emit(`help-wanted-clicked`, $event)\" />\n      <div class=\"clearfix\" />\n    </section>\n\n    <section v-if=\"modesLimited && modeNumberLoadLimit < fixture.modes.length\" class=\"card orange dark\">\n      <h2><OflSvg name=\"alert\" /> This fixture is big!</h2>\n\n      <div>Only the first {{ modeNumberLoadLimit }} of {{ fixture.modes.length }} modes are displayed. Loading more modes might take a while.</div>\n\n      <div class=\"button-bar\">\n        <a\n          v-if=\"isBrowser\"\n          href=\"#load-modes\"\n          class=\"button primary\"\n          @click.prevent=\"modeNumberLoadLimit += modeNumberLoadIncrement\">\n          Load {{ Math.min(modeNumberLoadIncrement, fixture.modes.length - modeNumberLoadLimit) }} more modes\n        </a>\n        <a\n          href=\"?loadAllModes\"\n          class=\"button\"\n          :class=\"isBrowser ? `secondary` : `primary`\"\n          rel=\"nofollow noindex\"\n          @click.prevent=\"modeNumberLoadLimit = undefined\">\n          Load all {{ fixture.modes.length }} modes\n        </a>\n      </div>\n    </section>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.fixture-info {\n  border-top: 0.4rem solid transparent;\n}\n\n.comment ::v-deep .value {\n  white-space: pre-line;\n}\n\n.fixture-videos {\n  padding: 0;\n  margin: 1rem 0 0;\n  line-height: 1;\n  text-align: center;\n}\n\n.fixture-video {\n  margin-bottom: 1rem;\n\n  @media screen and (min-width: $phone-landscape) {\n    display: inline-block;\n    width: 50%;\n  }\n\n  & a {\n    display: inline-block;\n    margin-top: 4px;\n  }\n}\n\n.fixture-links {\n  padding: 0;\n  margin: 0;\n  list-style: none;\n\n  .hostname {\n    padding-left: 1ex;\n    font-size: 0.9em;\n    color: theme-color(text-secondary);\n  }\n\n  .link-other {\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n}\n\n.wheels {\n  overflow: hidden;\n  overflow-x: auto;\n  white-space: nowrap;\n}\n</style>\n\n<script>\nimport { EmbettyVideo } from 'embetty-vue';\nimport { booleanProp, instanceOfProp } from 'vue-ts-types';\nimport register from '../../../fixtures/register.json';\nimport Fixture from '../../../lib/model/Fixture.js';\nimport { linksProperties } from '../../../lib/schema-properties.js';\nimport fixtureLinkTypes from '../../assets/scripts/fixture-link-types.js';\nimport CategoryBadge from '../../components/CategoryBadge.vue';\nimport FixturePageMatrix from '../../components/fixture-page/FixturePageMatrix.vue';\nimport FixturePageMode from '../../components/fixture-page/FixturePageMode.vue';\nimport FixturePagePhysical from '../../components/fixture-page/FixturePagePhysical.vue';\nimport FixturePageWheel from '../../components/fixture-page/FixturePageWheel.vue';\nimport HelpWantedMessage from '../../components/HelpWantedMessage.vue';\nimport LabeledValue from '../../components/LabeledValue.vue';\n\nconst VIDEOS_TO_EMBED = 2;\n\nexport default {\n  components: {\n    CategoryBadge,\n    EmbettyVideo,\n    FixturePageMatrix,\n    FixturePageMode,\n    FixturePagePhysical,\n    FixturePageWheel,\n    HelpWantedMessage,\n    LabeledValue,\n  },\n  props: {\n    fixture: instanceOfProp(Fixture).required,\n    loadAllModes: booleanProp().withDefault(false),\n  },\n  emits: {\n    'help-wanted-clicked': (payload) => true,\n  },\n  data() {\n    const { linkTypeIconNames, linkTypeNames } = fixtureLinkTypes;\n    return {\n      manufacturerColor: register.colors[this.fixture.manufacturer.key] || null,\n      isBrowser: false,\n      modeNumberLoadLimit: this.loadAllModes ? undefined : 5, // initially displayed modes, if limited\n      modeNumberLoadThreshold: 15, // fixtures with more modes will be limited\n      modeNumberLoadIncrement: 10, // how many modes a button click will load\n      linkTypeIconNames,\n      linkTypeNames,\n    };\n  },\n  computed: {\n    modesLimited() {\n      return this.fixture.modes.length > this.modeNumberLoadThreshold;\n    },\n    modes() {\n      const modes = this.fixture.modes;\n\n      if (!this.modesLimited) {\n        return modes;\n      }\n\n      return modes.slice(0, this.modeNumberLoadLimit);\n    },\n\n    /**\n     * @returns {object[]} Array of videos that can be embetted.\n     */\n    videos() {\n      const videoUrls = this.fixture.getLinksOfType('video');\n      const embettableVideoData = [];\n\n      for (const url of videoUrls) {\n        if (embettableVideoData.length === VIDEOS_TO_EMBED) {\n          break;\n        }\n\n        const videoData = getEmbettableVideoData(url);\n        if (videoData !== null) {\n          embettableVideoData.push(videoData);\n        }\n      }\n\n      return embettableVideoData;\n    },\n\n    links() {\n      const links = [];\n\n      for (const linkType of Object.keys(linksProperties)) {\n        let linkDisplayNumber = 1;\n        let linksOfType = this.fixture.getLinksOfType(linkType);\n\n        if (linkType === 'video') {\n          linksOfType = linksOfType.filter(\n            (url) => !this.videos.some((video) => video.url === url),\n          );\n          linkDisplayNumber += this.videos.length;\n        }\n\n        for (const url of linksOfType) {\n          let name = this.linkTypeNames[linkType];\n          const title = `${name} at ${url}`;\n\n          if (linkType === 'other') {\n            name = url;\n          }\n          else if (linkDisplayNumber > 1) {\n            name += ` ${linkDisplayNumber}`;\n          }\n\n          links.push({\n            url,\n            name,\n            title,\n            type: linkType,\n            iconName: this.linkTypeIconNames[linkType],\n            hostname: getHostname(url),\n          });\n\n          linkDisplayNumber++;\n        }\n      }\n\n      return links;\n    },\n  },\n  mounted() {\n    this.isBrowser = true;\n  },\n};\n\nconst supportedVideoFormats = {\n\n  native: {\n    regex: /\\.(?:mp4|avi)$/,\n    displayType: (url) => getHostname(url),\n    videoId: (url, match) => url,\n    startAt: (url, match) => 0,\n  },\n\n  youtube: {\n    /**\n     * YouTube videos can be in the following format:\n     * - https://www.youtube.com/watch?v={videoId}&otherParameters\n     */\n    regex: /^https:\\/\\/www\\.youtube\\.com\\/watch\\?v=([\\w-]+)(?:&t=([\\dhms]+)|)/,\n    displayType: (url) => 'YouTube',\n    videoId: (url, match) => match[1],\n    startAt: (url, match) => match[2] || 0,\n  },\n\n  vimeo: {\n    /**\n     * Vimeo videos can be in one of the following formats:\n     * - https://vimeo.com/{videoId}\n     * - https://vimeo.com/channels/{channelName}/{videoId}\n     * - https://vimeo.com/groups/{groupId}/videos/{videoId}\n     */\n    regex: /^https:\\/\\/vimeo.com\\/(?:channels\\/[^/]+\\/|groups\\/[^/]+\\/videos\\/)?(\\d+)(?:#t=([\\dhms]+))?/,\n    displayType: (url) => 'Vimeo',\n    videoId: (url, match) => match[1],\n    startAt: (url, match) => match[2] || 0,\n  },\n\n  facebook: {\n    /**\n     * Facebook videos can be in the following format:\n     * - https://www.facebook.com/{pageName}/videos/{videoTitle}/{videoId}/\n     */\n    regex: /^https:\\/\\/www\\.facebook\\.com\\/[^/]+\\/videos\\/[^/]+\\/(\\d+)\\/$/,\n    displayType: (url) => 'Facebook',\n    videoId: (url, match) => match[1],\n    startAt: (url, match) => 0,\n  },\n\n};\n\n/**\n * @param {string} url The video URL.\n * @returns {object | null} The embettable video data for the URL, or null if the video can not be embetted.\n */\nfunction getEmbettableVideoData(url) {\n  const videoTypes = Object.keys(supportedVideoFormats);\n\n  for (const type of videoTypes) {\n    const format = supportedVideoFormats[type];\n    const match = url.match(format.regex);\n\n    if (match) {\n      return {\n        url,\n        type,\n        displayType: format.displayType(url),\n        videoId: format.videoId(url, match),\n        startAt: format.startAt(url, match),\n      };\n    }\n  }\n\n  return null;\n}\n\n/**\n * @param {string} url The URL to extract the hostname from.\n * @returns {string} The hostname of the provided URL, or the whole URL if the hostname could not be determined.\n */\nfunction getHostname(url) {\n  // adapted from https://stackoverflow.com/a/21553982/451391\n  const match = url.match(/^.*?\\/\\/([^#/:?]*)(?::(\\d+)|)/);\n  return match ? match[1] : url;\n}\n\n</script>\n"
  },
  {
    "path": "ui/components/fixture-page/FixturePageCapabilityTable.vue",
    "content": "<template>\n  <table class=\"capabilities-table\">\n    <colgroup>\n      <col style=\"width: 5.8ex;\">\n      <col style=\"width: 1ex;\">\n      <col style=\"width: 5.8ex;\">\n      <col style=\"width: 1.8em;\">\n      <col>\n      <col style=\"width: 1.8em;\">\n    </colgroup>\n    <thead>\n      <tr>\n        <th colspan=\"3\" style=\"text-align: center;\">DMX values</th>\n        <th /> <!-- icon -->\n        <th>Capability</th>\n        <th /> <!-- menuClick -->\n      </tr>\n    </thead>\n    <tbody>\n      <template v-for=\"(cap, index) of capabilities\">\n        <tr :key=\"`cap-${index}`\" class=\"capability\" :data-capability-type=\"cap.model.type\">\n          <td class=\"capability-range0\"><code>{{ cap.dmxRangeStart }} </code></td>\n          <td class=\"capability-range-separator\"><code>…</code></td>\n          <td class=\"capability-range1\"><code>{{ cap.dmxRangeEnd }}</code></td>\n\n          <td class=\"capability-icon\">\n            <CapabilityTypeIcon :capability=\"cap.model\" />\n          </td>\n\n          <td class=\"capability-name\">{{ cap.model.name }}</td>\n\n          <td\n            :title=\"cap.model.menuClick === `hidden` ? `this capability is hidden in quick menus` : `choosing this capability in a quick menu snaps to ${cap.model.menuClick} of capability`\"\n            class=\"capability-menu-click\">\n            <OflSvg :name=\"`capability-${cap.model.menuClick}`\" />\n          </td>\n        </tr>\n\n        <tr\n          v-for=\"switchChannel of cap.switchChannels\"\n          :key=\"`cap-${index}-switch-${switchChannel.key}`\"\n          class=\"switch-to-channel\">\n          <td colspan=\"4\" />\n          <td colspan=\"2\">\n            <span class=\"switching-channel-key\">Channel&nbsp;{{ switchChannel.index + 1 }} →</span>&nbsp;{{ switchChannel.to }}\n          </td>\n        </tr>\n\n        <tr\n          v-if=\"cap.model.helpWanted !== null\"\n          :key=\"`cap-${index}-helpWanted`\">\n          <td colspan=\"4\" />\n          <td colspan=\"2\">\n            <HelpWantedMessage\n              type=\"capability\"\n              :context=\"cap.model\"\n              @help-wanted-clicked=\"$emit(`help-wanted-clicked`, $event)\" />\n          </td>\n        </tr>\n      </template>\n    </tbody>\n  </table>\n</template>\n\n<style lang=\"scss\" scoped>\n.capabilities-table {\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: collapse;\n}\n\nth {\n  font-weight: 400;\n  color: theme-color(text-secondary);\n}\n\ntd,\nth {\n  padding: 0 4px;\n  vertical-align: top;\n}\n\n.capability[data-capability-type=\"NoFunction\"],\n.capability[data-capability-type=\"NoFunction\"] + .switch-to-channel {\n  opacity: 0.6;\n}\n\n.capability-range0 {\n  padding-right: 2px;\n  text-align: right;\n}\n\n.capability-range-separator {\n  padding-right: 0;\n  padding-left: 0;\n  text-align: center;\n}\n\n.capability-range1 {\n  padding-left: 2px;\n  text-align: left;\n}\n\n.capability-icon .gobo-icon {\n  pointer-events: none;\n  transition: transform 0.4s;\n}\n\n.capability-icon:hover .gobo-icon {\n  z-index: 1;\n  transform: scale(4);\n}\n\n.capability-menu-click {\n  text-align: right;\n}\n\n.switch-to-channel > td {\n  padding-bottom: 4px;\n  font-size: 82%;\n  line-height: 1rem;\n\n  & > .switching-channel-key {\n    color: theme-color(text-secondary);\n  }\n}\n</style>\n\n<script>\nimport { instanceOfProp, numberProp } from 'vue-ts-types';\nimport CoarseChannel from '../../../lib/model/CoarseChannel.js';\nimport Mode from '../../../lib/model/Mode.js';\nimport CapabilityTypeIcon from '../CapabilityTypeIcon.vue';\nimport HelpWantedMessage from '../HelpWantedMessage.vue';\n\nexport default {\n  components: {\n    CapabilityTypeIcon,\n    HelpWantedMessage,\n  },\n  props: {\n    channel: instanceOfProp(CoarseChannel).required,\n    mode: instanceOfProp(Mode).required,\n    resolutionInMode: numberProp().required,\n  },\n  emits: {\n    'help-wanted-clicked': (payload) => true,\n  },\n  computed: {\n    capabilities() {\n      return this.channel.capabilities.map((capability) => {\n        const dmxRange = capability.getDmxRangeWithResolution(this.resolutionInMode);\n        const switchChannels = [];\n\n        for (const switchingChannelKey of Object.keys(capability.switchChannels)) {\n          const switchingChannelIndex = this.mode.getChannelIndex(switchingChannelKey);\n\n          if (switchingChannelIndex > -1) {\n            switchChannels.push({\n              key: switchingChannelKey,\n              index: switchingChannelIndex,\n              to: capability.switchChannels[switchingChannelKey],\n            });\n          }\n        }\n\n        return {\n          model: capability,\n          dmxRangeStart: dmxRange.start,\n          dmxRangeEnd: dmxRange.end,\n          switchChannels: switchChannels.toSorted((a, b) => a.index - b.index), // ascending indices\n        };\n      });\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/fixture-page/FixturePageChannel.vue",
    "content": "<template>\n  <li>\n    <ConditionalDetails class=\"channel\">\n      <template #summary>\n        <ChannelTypeIcon class=\"channel-type-icon\" :channel=\"channel\" />{{ channel.name }}<code v-if=\"channelKey\" class=\"channel-key\">{{ channelKey }}</code>{{ appendToHeading ? ` ${appendToHeading}` : `` }}\n        <OflSvg\n          v-if=\"channel.isHelpWanted\"\n          class=\"help-wanted-icon\"\n          name=\"comment-question-outline\"\n          title=\"Help wanted!\" />\n      </template>\n\n      <slot />\n\n      <div v-if=\"(channel instanceof FineChannel)\">\n        Fine channel of {{ channel.coarseChannel.name }} (channel&nbsp;{{ mode.getChannelIndex(channel.coarseChannel.key) + 1 }})\n      </div>\n\n      <template v-else-if=\"(channel instanceof SwitchingChannel)\">\n        <span>Switches depending on trigger channel's value.</span>\n\n        <LabeledValue\n          name=\"switchingChannel-triggerChannel\"\n          label=\"Trigger channel\">\n          {{ channel.triggerChannel.name }} (channel&nbsp;{{ mode.getChannelIndex(channel.triggerChannel.key) + 1 }})\n        </LabeledValue>\n\n        <ol>\n          <FixturePageChannel\n            v-for=\"(ranges, switchToChannelKey) of channel.triggerRanges\"\n            :key=\"switchToChannelKey\"\n            :channel=\"fixture.getChannelByKey(switchToChannelKey)\"\n            :mode=\"mode\"\n            :append-to-heading=\"channel.defaultChannel.key === switchToChannelKey ? `(default)` : null\"\n            @help-wanted-clicked=\"$emit(`help-wanted-clicked`, $event)\">\n            <LabeledValue\n              name=\"switchingChannel-triggerRanges\"\n              label=\"Activated when\">\n              Trigger channel is set to\n              <template v-for=\"(range, index) of ranges\">\n                {{ index > 0 ? ` or ` : `` }}\n                <span :key=\"range.toString()\" style=\"white-space: nowrap;\">\n                  {{ range.toString() }}\n                </span>\n              </template>\n            </LabeledValue>\n          </FixturePageChannel>\n        </ol>\n      </template>\n\n      <template v-if=\"channel.pixelKey !== null && !(channel instanceof SwitchingChannel)\">\n        <LabeledValue\n          v-if=\"fixture.matrix.pixelGroupKeys.includes(channel.pixelKey)\"\n          key=\"pixel-group\"\n          :value=\"`${channel.pixelKey}`\"\n          name=\"channel-pixel-group\"\n          label=\"Pixel group\" />\n\n        <template v-else>\n          <LabeledValue\n            key=\"pixel\"\n            :value=\"`${channel.pixelKey}`\"\n            name=\"channel-pixel-key\"\n            label=\"Pixel\" />\n          <LabeledValue\n            key=\"pixel-position\"\n            name=\"channel-pixel-position\"\n            label=\"Pixel position\">\n            ({{ fixture.matrix.pixelKeyPositions[channel.pixelKey][0] }},\n            {{ fixture.matrix.pixelKeyPositions[channel.pixelKey][1] }},\n            {{ fixture.matrix.pixelKeyPositions[channel.pixelKey][2] }})\n            <span class=\"hint\">(X, Y, Z)</span>\n          </LabeledValue>\n        </template>\n      </template>\n\n      <template v-if=\"(channel instanceof CoarseChannel)\">\n        <LabeledValue\n          v-if=\"resolutionInMode > CoarseChannel.RESOLUTION_8BIT\"\n          key=\"fine-channels\"\n          name=\"channel-fineChannelAliases\"\n          label=\"Fine channels\">\n          {{ channel.fineChannels.slice(0, resolutionInMode - 1).map(\n            fineChannel => `${fineChannel.name} (channel&nbsp;${mode.getChannelIndex(fineChannel.key) + 1})`,\n          ).join(`, `) }}\n        </LabeledValue>\n\n        <LabeledValue\n          v-if=\"channel.hasDefaultValue\"\n          key=\"default-value\"\n          :value=\"`${channel.getDefaultValueWithResolution(resolutionInMode)}`\"\n          name=\"channel-defaultValue\"\n          label=\"Default DMX value\" />\n\n        <LabeledValue\n          v-if=\"channel.hasHighlightValue\"\n          key=\"highlight-value\"\n          :value=\"`${channel.getHighlightValueWithResolution(resolutionInMode)}`\"\n          name=\"channel-highlightValue\"\n          label=\"Highlight DMX value\" />\n\n        <LabeledValue\n          v-if=\"channel.isInverted\"\n          key=\"is-inverted\"\n          name=\"channel-isInverted\"\n          label=\"Is inverted?\"\n          value=\"Yes\" />\n\n        <LabeledValue\n          v-if=\"channel.isConstant\"\n          key=\"is-constant\"\n          name=\"channel-isConstant\"\n          label=\"Is constant?\"\n          value=\"Yes\" />\n\n        <LabeledValue\n          v-if=\"channel.canCrossfade\"\n          key=\"can-crossfade\"\n          name=\"channel-canCrossfade\"\n          label=\"Can crossfade?\"\n          value=\"Yes\" />\n\n        <LabeledValue\n          v-if=\"channel.precedence !== `LTP`\"\n          key=\"precedence\"\n          :value=\"channel.precedence\"\n          name=\"channel-precedence\"\n          label=\"Precedence\" />\n\n        <FixturePageCapabilityTable\n          :channel=\"channel\"\n          :mode=\"mode\"\n          :resolution-in-mode=\"resolutionInMode\"\n          @help-wanted-clicked=\"$emit(`help-wanted-clicked`, $event)\" />\n      </template>\n\n    </ConditionalDetails>\n  </li>\n</template>\n\n<style lang=\"scss\" scoped>\n.channel-type-icon {\n  margin-right: 1.2ex;\n}\n\n.help-wanted-icon {\n  margin-left: 0.7ex;\n  fill: theme-color(yellow-background-hover);\n}\n</style>\n\n<script>\nimport { instanceOfProp, stringProp } from 'vue-ts-types';\nimport AbstractChannel from '../../../lib/model/AbstractChannel.js';\nimport CoarseChannel from '../../../lib/model/CoarseChannel.js';\nimport FineChannel from '../../../lib/model/FineChannel.js';\nimport Mode from '../../../lib/model/Mode.js';\nimport NullChannel from '../../../lib/model/NullChannel.js';\nimport SwitchingChannel from '../../../lib/model/SwitchingChannel.js';\nimport ChannelTypeIcon from '../ChannelTypeIcon.vue';\nimport ConditionalDetails from '../ConditionalDetails.vue';\nimport LabeledValue from '../LabeledValue.vue';\nimport FixturePageCapabilityTable from './FixturePageCapabilityTable.vue';\n\nexport default {\n  name: 'FixturePageChannel',\n  components: {\n    ConditionalDetails,\n    ChannelTypeIcon,\n    FixturePageCapabilityTable,\n    LabeledValue,\n  },\n  props: {\n    channel: instanceOfProp(AbstractChannel).required,\n    mode: instanceOfProp(Mode).required,\n    appendToHeading: stringProp().optional,\n  },\n  emits: {\n    'help-wanted-clicked': (payload) => true,\n  },\n  data() {\n    return {\n      CoarseChannel,\n      FineChannel,\n      SwitchingChannel,\n      fixture: this.mode.fixture,\n    };\n  },\n  computed: {\n    channelKey() {\n      if (this.channel instanceof NullChannel) {\n        return 'null';\n      }\n\n      if (this.channel.key !== this.channel.name) {\n        return this.channel.key;\n      }\n\n      return '';\n    },\n    resolutionInMode() {\n      return this.channel.getResolutionInMode(this.mode);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/fixture-page/FixturePageMatrix.vue",
    "content": "<template>\n  <div class=\"matrix\">\n    <section class=\"structure\">\n      <div v-for=\"(zLevel, zIndex) of matrix.pixelKeyStructure\" :key=\"zIndex\" class=\"z-level\">\n        <div v-for=\"(row, yIndex) of zLevel\" :key=\"yIndex\" class=\"row\">\n          <div\n            v-for=\"(pixelKey, xIndex) of row\"\n            :key=\"xIndex\"\n            :style=\"pixelSizing\"\n            class=\"pixel\"\n            :class=\"{ highlight: highlightedPixelKeys.includes(pixelKey) }\">{{ pixelKey || '' }}</div>\n        </div>\n      </div>\n      <span class=\"hint\">Front view</span>\n    </section>\n\n    <section v-if=\"pixelGroups.length > 0\" class=\"pixel-groups\">\n      <h4>Pixel groups</h4>\n      <span class=\"hint only-js\">Hover over the pixel groups to highlight the corresponding pixels.</span>\n\n      <div>\n        <LabeledValue\n          v-for=\"[key, value] of pixelGroups\"\n          :key=\"key\"\n          :label=\"key\"\n          :value=\"value\"\n          name=\"pixel-group\"\n          tabindex=\"0\"\n          @mouseover=\"highlightedPixelKeys = matrix.pixelGroups[key]\"\n          @focusin=\"highlightedPixelKeys = matrix.pixelGroups[key]\"\n          @mouseout=\"highlightedPixelKeys = []\"\n          @focusout=\"highlightedPixelKeys = []\" />\n      </div>\n    </section>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.z-level {\n  padding-top: 1px;\n  padding-left: 1px;\n  margin-bottom: 8px;\n  overflow: auto;\n  border-spacing: 0;\n  border-collapse: collapse;\n}\n\n.row {\n  display: block;\n  margin-top: -1px;\n  white-space: nowrap;\n}\n\n.pixel {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  margin-left: -1px;\n  font-size: 90%;\n  line-height: 1.4em;\n  vertical-align: top;\n  text-align: center;\n  white-space: normal;\n  border: 1px solid transparent;\n  transition: background-color 0.2s;\n\n  &:not(:empty) {\n    background-color: theme-color(card-background);\n    border-color: theme-color(icon-inactive);\n  }\n\n  &.highlight {\n    background-color: theme-color(divider);\n  }\n}\n\n.pixel-groups > div {\n  max-height: 32vh;\n  overflow: auto;\n}\n</style>\n\n<script>\nimport { instanceOfProp } from 'vue-ts-types';\nimport Matrix from '../../../lib/model/Matrix.js';\nimport Physical from '../../../lib/model/Physical.js';\nimport LabeledValue from '../LabeledValue.vue';\n\nexport default {\n  components: {\n    LabeledValue,\n  },\n  props: {\n    matrix: instanceOfProp(Matrix).required,\n    physical: instanceOfProp(Physical).optional,\n  },\n  data() {\n    return {\n      highlightedPixelKeys: [],\n      baseHeight: 3.2, // in em\n    };\n  },\n  computed: {\n    pixelSizing() {\n      let sizing = `height: ${this.baseHeight}em; `;\n\n      if (this.physical?.hasMatrixPixels) {\n        const scale = this.baseHeight / this.physical.matrixPixelsDimensions[1];\n        sizing += `width: ${this.physical.matrixPixelsDimensions[0] * scale}em; `;\n        sizing += `margin-right: ${this.physical.matrixPixelsSpacing[0] * scale}em; `;\n        sizing += `margin-bottom: ${this.physical.matrixPixelsSpacing[1] * scale}em; `;\n      }\n      else {\n        sizing += `width: ${this.baseHeight}em; `;\n      }\n\n      return sizing;\n    },\n\n    pixelGroups() {\n      return this.matrix.pixelGroupKeys.map((groupKey) => {\n        const group = this.matrix.jsonObject.pixelGroups[groupKey];\n        const resolvedPixelsKeys = this.matrix.pixelGroups[groupKey];\n\n        if (group === 'all') {\n          return [groupKey, 'All pixels'];\n        }\n\n        const constraintAxes = ['x', 'y', 'z'].filter((axis) => axis in group);\n\n        const shouldShowPixelKeyArray = Array.isArray(group) || resolvedPixelsKeys.length <= 5 || constraintAxes.some(\n          (axis) => group[axis].some((constraint) => /^\\d+n/.test(constraint)),\n        ) || constraintAxes.length > 2 || 'name' in group;\n\n        if (shouldShowPixelKeyArray) {\n          return [groupKey, resolvedPixelsKeys.join(', ')];\n        }\n\n        const constraintText = constraintAxes.map((axis) => {\n          const axisConstraints = group[axis].map(\n            (constraint) => constraint.replace('>=', '≥ ').replace('<=', '≤ ').replace('=', ''),\n          ).join(', ');\n\n          return `${axis.toUpperCase()} coordinate is ${axisConstraints}`;\n        }).join(' and ');\n\n        return [groupKey, `Pixels where ${constraintText}`];\n      });\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/fixture-page/FixturePageMode.vue",
    "content": "<template>\n  <section\n    :id=\"mode.rdmPersonalityIndex === null ? null : `rdm-personality-${mode.rdmPersonalityIndex}`\"\n    class=\"fixture-mode card\">\n\n    <h2>{{ mode.name }} mode <code v-if=\"mode.hasShortName\">{{ mode.shortName }}</code></h2>\n\n    <span v-if=\"mode.rdmPersonalityIndex !== null\" class=\"hint\">RDM personality index: {{ mode.rdmPersonalityIndex }}</span>\n\n    <template v-if=\"mode.physicalOverride !== null\">\n      <h3>Physical overrides</h3>\n      <section class=\"physical physical-override\">\n        <FixturePagePhysical :physical=\"mode.physicalOverride\" />\n      </section>\n    </template>\n\n    <h3>DMX channels<template v-if=\"showCollapseExpandButtons\">\n      <button\n        type=\"button\"\n        class=\"icon-button expand-all only-js\"\n        title=\"Expand all channels\"\n        @click.prevent=\"openDetails()\">\n        <OflSvg name=\"chevron-double-down\" />\n      </button>\n      <button\n        type=\"button\"\n        class=\"icon-button collapse-all only-js\"\n        title=\"Collapse all channels\"\n        @click.prevent=\"closeDetails()\">\n        <OflSvg name=\"chevron-double-up\" />\n      </button>\n    </template></h3>\n\n    <ol class=\"mode-channels\">\n      <FixturePageChannel\n        v-for=\"channel of mode.channels\"\n        :key=\"channel.key\"\n        :channel=\"channel\"\n        :mode=\"mode\"\n        @help-wanted-clicked=\"$emit(`help-wanted-clicked`, $event)\" />\n    </ol>\n\n  </section>\n</template>\n\n<style lang=\"scss\" scoped>\n.expand-all,\n.collapse-all {\n  margin-left: 1ex;\n  font-size: 0.8rem;\n}\n\nol.mode-channels {\n  min-height: 1em;\n  padding-left: 1.9em;\n\n  // switched channels\n  ::v-deep ol {\n    padding-left: 1.1em;\n    list-style-type: lower-alpha;\n  }\n}\n</style>\n\n<script>\nimport { instanceOfProp } from 'vue-ts-types';\nimport Mode from '../../../lib/model/Mode.js';\nimport FixturePageChannel from './FixturePageChannel.vue';\nimport FixturePagePhysical from './FixturePagePhysical.vue';\n\nexport default {\n  components: {\n    FixturePageChannel,\n    FixturePagePhysical,\n  },\n  props: {\n    mode: instanceOfProp(Mode).required,\n  },\n  emits: {\n    'help-wanted-clicked': (payload) => true,\n  },\n  data() {\n    return {\n      hasDetails: true,\n    };\n  },\n  computed: {\n    showCollapseExpandButtons() {\n      return this.mode.channels.length > 1 && this.hasDetails;\n    },\n  },\n  async mounted() {\n    // wait for all child components to render\n    await this.$nextTick();\n\n    if (!this.$el.querySelector('details')) {\n      this.hasDetails = false;\n    }\n  },\n  methods: {\n    openDetails() {\n      for (const details of this.$el.querySelectorAll('details')) {\n        details.open = true;\n      }\n    },\n    closeDetails() {\n      for (const details of this.$el.querySelectorAll('details')) {\n        details.open = false;\n      }\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/fixture-page/FixturePagePhysical.vue",
    "content": "<template>\n  <div class=\"physical\">\n\n    <section>\n      <LabeledValue\n        v-if=\"physical.dimensions !== null\"\n        name=\"dimensions\"\n        label=\"Dimensions\">\n        {{ physical.width }} &times;\n        {{ physical.height }} &times;\n        {{ physical.depth }}mm\n        <span class=\"hint\">width &times; height &times; depth</span>\n      </LabeledValue>\n\n      <LabeledValue\n        v-if=\"physical.weight !== null\"\n        key=\"weight\"\n        name=\"weight\"\n        label=\"Weight\">\n        {{ physical.weight }}kg\n      </LabeledValue>\n\n      <LabeledValue\n        v-if=\"physical.power !== null\"\n        key=\"power\"\n        name=\"power\"\n        label=\"Power\">\n        {{ physical.power }}W\n      </LabeledValue>\n\n      <LabeledValue\n        v-if=\"physical.DMXconnector !== null\"\n        key=\"dmx-connector\"\n        name=\"DMXconnector\"\n        label=\"DMX connector\">\n        {{ physical.DMXconnector }}\n      </LabeledValue>\n    </section>\n\n    <section v-if=\"powerConnectors.length > 0\" class=\"power\">\n      <h4>Power connectors</h4>\n\n      <LabeledValue\n        v-for=\"connector of powerConnectors\"\n        :key=\"connector.name\"\n        :name=\"connector.name\"\n        :label=\"connector.name\">\n        {{ connector.value }}\n      </LabeledValue>\n    </section>\n\n    <section v-if=\"physical.hasBulb\" class=\"bulb\">\n      <h4>Bulb</h4>\n\n      <LabeledValue\n        v-if=\"physical.bulbType !== null\"\n        key=\"bulb-type\"\n        name=\"bulb-type\"\n        label=\"Bulb type\">\n        {{ physical.bulbType }}\n      </LabeledValue>\n\n      <LabeledValue\n        v-if=\"physical.bulbColorTemperature !== null\"\n        key=\"bulb-color-temperature\"\n        name=\"bulb-colorTemperature\"\n        label=\"Color temperature\">\n        {{ physical.bulbColorTemperature }}K\n      </LabeledValue>\n\n      <LabeledValue\n        v-if=\"physical.bulbLumens !== null\"\n        key=\"bulb-lumens\"\n        name=\"bulb-lumens\"\n        label=\"Lumens\">\n        {{ physical.bulbLumens }}lm\n      </LabeledValue>\n    </section>\n\n    <section v-if=\"physical.hasLens\" class=\"lens\">\n      <h4>Lens</h4>\n\n      <LabeledValue\n        v-if=\"physical.lensName !== null\"\n        key=\"lens-name\"\n        name=\"lens-name\"\n        label=\"Name\">\n        {{ physical.lensName }}\n      </LabeledValue>\n\n      <LabeledValue\n        v-if=\"physical.lensDegreesMin !== null\"\n        key=\"lens-degrees\"\n        name=\"lens-degreesMinMax\"\n        label=\"Beam angle\">\n        {{ physical.lensDegreesMin === physical.lensDegreesMax\n          ? `${physical.lensDegreesMin}°`\n          : `${physical.lensDegreesMin}…${physical.lensDegreesMax}°`\n        }}\n      </LabeledValue>\n    </section>\n\n    <section v-if=\"physical.hasMatrixPixels\" class=\"matrixPixels\">\n      <h4>Matrix Pixels</h4>\n\n      <LabeledValue\n        v-if=\"physical.matrixPixelsDimensions !== null\"\n        key=\"pixel-dimensions\"\n        name=\"dimensions\"\n        label=\"Pixel dimensions\">\n        {{ physical.matrixPixelsDimensions[0] }} &times;\n        {{ physical.matrixPixelsDimensions[1] }} &times;\n        {{ physical.matrixPixelsDimensions[2] }}mm\n        <span class=\"hint\">width &times; height &times; depth</span>\n      </LabeledValue>\n\n      <LabeledValue\n        v-if=\"physical.matrixPixelsSpacing !== null\"\n        key=\"pixel-spacing\"\n        name=\"dimensions\"\n        label=\"Pixel spacing\">\n        {{ physical.matrixPixelsSpacing[0] }} &times;\n        {{ physical.matrixPixelsSpacing[1] }} &times;\n        {{ physical.matrixPixelsSpacing[2] }}mm\n        <span class=\"hint\">left/right &times; top/bottom &times; ahead/aback</span>\n      </LabeledValue>\n    </section>\n\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.physical {\n  columns: 2 350px;\n  column-gap: 3rem;\n\n  & > section {\n    padding: 0 0 1.2ex;\n    overflow: hidden;\n    break-inside: avoid;\n\n    &:empty {\n      display: none;\n    }\n  }\n\n  h4 {\n    margin: 0;\n  }\n}\n</style>\n\n<script>\nimport { instanceOfProp } from 'vue-ts-types';\nimport Physical from '../../../lib/model/Physical.js';\nimport LabeledValue from '../LabeledValue.vue';\n\nexport default {\n  components: {\n    LabeledValue,\n  },\n  props: {\n    physical: instanceOfProp(Physical).required,\n  },\n  computed: {\n    powerConnectors() {\n      return Object.entries(this.physical.powerConnectors).map(([name, value]) => ({\n        name,\n        value,\n      }));\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/fixture-page/FixturePageWheel.vue",
    "content": "<template>\n  <figure class=\"wheel\">\n    <svg\n      :width=\"300\"\n      :height=\"300\"\n      :viewBox=\"`${-wheelRadius} ${-wheelRadius} ${2 * wheelRadius} ${2 * wheelRadius}`\">\n\n      <defs>\n        <radialGradient id=\"frostGradient\">\n          <stop offset=\"0\" stop-color=\"#fff\" />\n          <stop offset=\"0.6\" stop-color=\"#fff\" />\n          <stop offset=\"1\" stop-color=\"#000\" />\n        </radialGradient>\n      </defs>\n\n      <circle\n        cx=\"0\"\n        cy=\"0\"\n        :r=\"wheelRadius\"\n        fill=\"#444\"\n        class=\"wheel\" />\n      <circle\n        cx=\"0\"\n        cy=\"0\"\n        r=\"3\"\n        fill=\"#fff\"\n        class=\"hole\" />\n\n      <g :transform=\"`scale(${wheel.direction === `CCW` ? -1 : 1}, 1)`\" class=\"arrow\">\n        <g transform=\"rotate(-30)\">\n          <path\n            d=\"M 0,-6 C 3,-6 6,-3 6,0\"\n            fill=\"none\"\n            stroke=\"#aaa\"\n            stroke-width=\"1\" />\n          <path\n            d=\"M 0,-8 -4,-6 0,-4 Z\"\n            fill=\"#aaa\" />\n        </g>\n      </g>\n\n      <g\n        v-for=\"(slot, index) of wheel.slots\"\n        :key=\"`slot-${index}`\"\n        :transform=\"`rotate(${slotRotateAngle * index}, 0, 0)`\"\n        class=\"slot\"\n        :class=\"{ dim: highlightedSlot !== null && highlightedSlot !== index }\">\n\n        <title>{{ slotTitles[index] }}</title>\n\n        <g\n          v-if=\"slot.colors !== null\"\n          :transform=\"`translate(0, ${slotRotateRadius})`\"\n          v-html=\"slotSvgFragments[index]\" />\n\n        <template v-else-if=\"slot.type === `Iris`\">\n          <circle\n            :cx=\"0\"\n            :cy=\"slotRotateRadius\"\n            :r=\"slotRadius\"\n            fill=\"#000\" />\n          <circle\n            :cx=\"0\"\n            :cy=\"slotRotateRadius\"\n            :r=\"slotRadius * (slot.openPercent ? slot.openPercent.number : 100) / 100\"\n            fill=\"#fff\" />\n        </template>\n\n        <circle\n          v-else-if=\"slot.type === `Frost`\"\n          :cx=\"0\"\n          :cy=\"slotRotateRadius\"\n          :r=\"slotRadius\"\n          fill=\"url(#frostGradient)\" />\n\n        <template v-else-if=\"slot.type === `AnimationGoboStart`\">\n          <!-- use circle's stroke, see https://css-tricks.com/building-a-donut-chart-with-vue-and-svg/ -->\n          <circle\n            :cx=\"0\"\n            :cy=\"0\"\n            :r=\"Math.abs(slotRotateRadius)\"\n            :stroke-width=\"2 * slotRadius\"\n            :stroke-dasharray=\"slotCircumference\"\n            :stroke-dashoffset=\"wheelDirectionFactor * (slotCircumference - animationGoboWidth)\"\n            :transform=\"`rotate(${-90 - (wheelDirectionFactor * slotRadius / slotCircumference * 360)}, 0, 0)`\"\n            stroke=\"#fff\"\n            fill=\"none\" />\n\n          <text\n            :x=\"0\"\n            :y=\"slotRotateRadius + slotRadius * 0.35\"\n            :transform=\"`rotate(${-slotRotateAngle * index}, 0, ${slotRotateRadius})`\"\n            :font-size=\"slotRadius\"\n            text-anchor=\"middle\"\n            fill=\"#000\">\n            S\n          </text>\n\n          <!-- rotate once more (like it was drawn in next slot) -->\n          <g :transform=\"`rotate(${slotRotateAngle}, 0, 0)`\">\n            <text\n              :x=\"0\"\n              :y=\"slotRotateRadius + slotRadius * 0.35\"\n              :transform=\"`rotate(${-slotRotateAngle * (index + 1)}, 0, ${slotRotateRadius})`\"\n              :font-size=\"slotRadius\"\n              text-anchor=\"middle\"\n              fill=\"#000\">\n              E\n            </text>\n          </g>\n        </template>\n\n        <template v-else-if=\"slot.type !== `AnimationGoboEnd`\">\n          <circle\n            :cx=\"0\"\n            :cy=\"slotRotateRadius\"\n            :r=\"slotRadius\"\n            fill=\"#fff\" />\n\n          <image\n            v-if=\"slot.resource && slot.resource.hasImage\"\n            :x=\"-slotRadius\"\n            :y=\"slotRotateRadius - slotRadius\"\n            :width=\"slotRadius * 2\"\n            :height=\"slotRadius * 2\"\n            :xlink:href=\"slot.resource.imageDataUrl\" />\n\n          <text\n            v-else\n            :x=\"0\"\n            :y=\"slotRotateRadius + slotRadius * 0.35\"\n            :transform=\"`rotate(${-slotRotateAngle * index}, 0, ${slotRotateRadius})`\"\n            :font-size=\"slotRadius\"\n            text-anchor=\"middle\"\n            fill=\"#000\">\n            {{ slot.nthOfType + 1 }}\n          </text>\n        </template>\n      </g>\n    </svg>\n    <figcaption>\n      <ConditionalDetails>\n        <template #summary>{{ wheel.name }}</template>\n\n        <table>\n          <tbody>\n            <tr\n              v-for=\"(slot, index) of wheel.slots\"\n              :key=\"`slot-${index}`\"\n              tabindex=\"0\"\n              @mouseover=\"highlightedSlot = (slot.type === `AnimationGoboEnd` ? index - 1 : index)\"\n              @focusin=\"highlightedSlot = (slot.type === `AnimationGoboEnd` ? index - 1 : index)\"\n              @mouseout=\"highlightedSlot = null\"\n              @focusout=\"highlightedSlot = null\">\n              <th scope=\"row\">Slot {{ index + 1 }}</th>\n              <td>{{ slot.name }}</td>\n            </tr>\n          </tbody>\n        </table>\n\n      </ConditionalDetails>\n    </figcaption>\n  </figure>\n</template>\n\n<style lang=\"scss\" scoped>\nfigure {\n  box-sizing: border-box;\n  display: inline-block;\n  width: 32%;\n  min-width: 18rem;\n  padding: 0 1rem;\n  margin: 0 0 0.5rem;\n  vertical-align: top;\n  white-space: normal;\n}\n\nsvg {\n  width: 100%;\n  height: 100%;\n}\n\n.slot {\n  & text {\n    font-weight: 400;\n    pointer-events: none;\n    fill: $primary-text-dark;\n  }\n\n  &:hover {\n    opacity: 0.7;\n  }\n\n  &.dim {\n    opacity: 0.3;\n  }\n}\n\nfigcaption ::v-deep summary {\n  position: sticky;\n  top: 0;\n  font-weight: 700;\n  text-align: center;\n\n  &:not(:hover, :focus) {\n    background: theme-color(card-background, 80%);\n  }\n}\n\nfigcaption {\n  max-height: 50vh;\n  overflow: auto;\n}\n\nfigcaption table {\n  border-spacing: 0;\n\n  & td,\n  & th {\n    padding: 3px;\n    vertical-align: top;\n  }\n\n  th {\n    white-space: nowrap;\n  }\n}\n</style>\n\n<script>\nimport { instanceOfProp } from 'vue-ts-types';\nimport Wheel from '../../../lib/model/Wheel.js';\nimport ConditionalDetails from '../ConditionalDetails.vue';\nimport { getColorCircleSvgFragment } from '../global/OflSvg.vue';\n\nexport default {\n  components: {\n    ConditionalDetails,\n  },\n  props: {\n    wheel: instanceOfProp(Wheel).required,\n  },\n  data() {\n    return {\n      highlightedSlot: null,\n      wheelRadius: 50,\n      wheelPadding: 3,\n    };\n  },\n  computed: {\n    wheelDirectionFactor() {\n      return this.wheel.direction === 'CCW' ? -1 : 1;\n    },\n    slotRadius() {\n      const usableRadius = this.wheelRadius - this.wheelPadding;\n\n      const spacingFactor = 0.85;\n      const anglePerSlot = (2 * Math.PI / this.wheel.slots.length) * spacingFactor; // radians\n\n      const maximumRadius = (usableRadius / 2) - 5; // preserve some space in the middle\n\n      // (I):       slotRotateRadius = slotRadius / sin(anglePerSlot / 2)\n      // (II):      slotRadius + slotRotateRadius = usableRadius\n      // (I in II): slotRadius + slotRadius / sin(anglePerSlot / 2) = usableRadius\n      //            slotRadius * (1 + 1 / sin(anglePerSlot / 2)) = usableRadius\n      //            slotRadius = usableRadius / (1 + 1 / sin(anglePerSlot / 2))\n      return Math.min(usableRadius / (1 + (1 / Math.sin(anglePerSlot / 2))), maximumRadius);\n    },\n    slotRotateRadius() {\n      return -this.wheelRadius + this.slotRadius + this.wheelPadding;\n    },\n    slotRotateAngle() {\n      return 360 / this.wheel.slots.length * this.wheelDirectionFactor;\n    },\n    slotCircumference() {\n      return 2 * Math.PI * Math.abs(this.slotRotateRadius);\n    },\n    slotSvgFragments() {\n      return this.wheel.slots.map((slot) => {\n        if (slot.colors !== null) {\n          return getColorCircleSvgFragment(slot.colors, this.slotRadius);\n        }\n\n        return null;\n      });\n    },\n    animationGoboWidth() {\n      if (this.wheel.slots.length === 2) {\n        // wheel only contains AnimationGoboStart and AnimationGoboEnd\n        return this.slotCircumference;\n      }\n\n      return (2 * this.slotRadius) + (this.slotCircumference * Math.abs(this.slotRotateAngle) / 360);\n    },\n    slotTitles() {\n      return this.wheel.slots.map((slot, index) => {\n        if (slot.type === 'AnimationGoboStart') {\n          const splitSlot = this.wheel.getSlot(index + 1.5);\n          return `Slots ${index + 1}…${index + 2}: ${splitSlot.name}`;\n        }\n\n        return `Slot ${index + 1}: ${slot.name}`;\n      });\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/components/global/OflSvg.vue",
    "content": "<!-- eslint-disable-next-line vue/enforce-style-attribute -- scoped styles don't work for functional components -->\n<style lang=\"scss\">\n.icon {\n  display: inline-block;\n  width: 1.4em;\n  height: 1.4em;\n  vertical-align: middle;\n\n  &.inactive {\n    fill: theme-color(icon-inactive);\n  }\n\n  &.gobo-icon {\n    box-sizing: border-box;\n    padding: 2px;\n    background-color: white;\n    background-clip: content-box;\n    border-radius: 50%;\n  }\n\n  & svg {\n    display: block;\n    width: 100%;\n    height: 100%;\n  }\n}\n</style>\n\n<script>\nimport { arrayProp, stringProp } from 'vue-ts-types';\nimport icons from '../../assets/icons/icons.js';\n\nexport default {\n  functional: true,\n  props: {\n    type: stringProp().optional,\n    name: stringProp().optional,\n    colors: arrayProp().withDefault(() => []),\n    title: stringProp().optional,\n  },\n  render(createElement, context) {\n    let svgMarkup;\n    let hasTitle = Boolean(context.props.title);\n\n    if (context.props.type === 'color-circle') {\n      let colors = context.props.colors;\n\n      if (context.props.colors.length === 0 && context.props.name !== undefined) {\n        // hex colors for ColorIntensity capabilities\n        const colorLookup = {\n          'Red': '#ff0000',\n          'Green': '#00ff00',\n          'Blue': '#0000ff',\n          'Cyan': '#00ffff',\n          'Magenta': '#ff00ff',\n          'Yellow': '#ffff00',\n          'Amber': '#ffbf00',\n          'White': '#ffffff',\n          'Warm White': '#ffedde',\n          'Cold White': '#edefff',\n          'UV': '#8800ff',\n          'Lime': '#bfff00',\n          'Indigo': '#4b0082',\n        };\n        colors = [colorLookup[context.props.name]];\n      }\n\n      const title = context.props.title || context.props.name;\n      hasTitle = Boolean(title);\n      svgMarkup = getColorCircle(colors, title);\n    }\n    else {\n      svgMarkup = getSvg(context.props.name, context.props.type, context.props.title);\n    }\n\n    return createElement('span', {\n      ...context.data,\n      class: ['icon', context.data.class],\n      attrs: hasTitle ? {} : { 'aria-hidden': 'true' },\n      domProps: {\n        innerHTML: svgMarkup,\n      },\n    });\n  },\n};\n\n/**\n * Returns the contents of the provided SVG file as an inline SVG.\n * @param {string | undefined} name Name of the icon (without extension).\n * @param {string | undefined} category The category (directory) of the icon.\n * @param {string | undefined} title An optional (tooltip) title for the icon.\n * @returns {string} The inline <svg> tag or an empty string if the file was not found.\n */\nfunction getSvg(name, category = undefined, title) {\n  if (name === undefined) {\n    return '';\n  }\n\n  const kebabName = name.replaceAll(/([a-z])([A-Z])/g, '$1-$2').toLowerCase().replaceAll(/\\W+/g, '-');\n  const svgBasename = (category ? `${category}/` : '') + kebabName;\n  let svg;\n\n  if (svgBasename in icons) {\n    svg = icons[svgBasename].trim();\n  }\n  else {\n    throw new Error(`Icon '${svgBasename}' not found`);\n  }\n\n  svg = svg.replace('<svg', '<svg role=\"img\"');\n\n  if (title) {\n    svg = svg.replace(/(<svg[^>]*)>/, `$1 aria-label=\"${title}\"><title>${title}</title>`);\n  }\n\n  return svg;\n}\n\n/**\n * Get inline SVG for a color circle (like a pie chart with equally-sized pies).\n * @param {string[]} colors Array of color strings to display.\n * @param {string | undefined} [title] Text for the title tag. If this parameter is not given, no title tag will be added.\n * @returns {string} The HTML for displaying the color circle.\n */\nfunction getColorCircle(colors, title) {\n  // viewBox customized to have the (0,0) coordinate in the center\n  let string = '<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"24\" height=\"24\" viewBox=\"-12 -12 24 24\" class=\"icon color-circle\" role=\"img\">';\n\n  if (title) {\n    string += `<title>${title}</title>`;\n  }\n\n  const radius = 9;\n\n  // use current fill color as background / border\n  string += `<circle cx=\"0\" cy=\"0\" r=\"${radius + 1}\" />`;\n\n  string += getColorCircleSvgFragment(colors, radius);\n\n  string += '</svg>';\n\n  return string;\n}\n\n/**\n * @param {string[]} colors An array of hex colors to fill into the circle.\n * @param {number} radius The radius of the circle.\n * @returns {string} A string containing one SVG <circle> element or multiple SVG <path> elements.\n */\nexport function getColorCircleSvgFragment(colors, radius) {\n  if (colors.length === 1) {\n    return `<circle cx=\"0\" cy=\"0\" r=\"${radius}\" fill=\"${colors[0]}\" />`;\n  }\n\n  let svgString = '';\n  const slicePercent = 1 / colors.length;\n\n  const xAxisRotation = 0;\n  const largeArcFlag = 0;\n  const sweepFlag = 1;\n\n  for (const [index, color] of colors.entries()) {\n    const [startX, startY] = getCoordinatesForPercent(index * slicePercent, radius);\n    const [endX, endY] = getCoordinatesForPercent((index + 1) * slicePercent, radius);\n\n    const pathMove = `M ${startX} ${startY}`;\n    const pathArc = `A ${radius} ${radius} ${xAxisRotation} ${largeArcFlag} ${sweepFlag} ${endX} ${endY}`;\n    const pathLine = 'L 0 0';\n\n    svgString += `<path d=\"${pathMove} ${pathArc} ${pathLine}\" fill=\"${color}\" />`;\n  }\n\n  return svgString;\n}\n\n/**\n * Get x and y coordinates of the point that is `percent` percent of the way around a circle. Note that 37.5% are added to start at a 135deg angle.\n * @param {number} percent Percent of the whole circle.\n * @param {number} radius Radius of the circle.\n * @returns {[number, number]} Array with x and y coordinate.\n */\nfunction getCoordinatesForPercent(percent, radius) {\n  percent += 0.375;\n\n  const x = radius * Math.cos(2 * Math.PI * percent);\n  const y = radius * Math.sin(2 * Math.PI * percent);\n  return [x, y];\n}\n</script>\n"
  },
  {
    "path": "ui/components/global/OflTime.vue",
    "content": "<template>\n  <time :datetime=\"isoDate\" :title=\"isoDate\">{{\n    isoDate.replace(/T.*?$/, ``)\n  }}</time>\n</template>\n\n<script>\nimport { instanceOfProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    date: instanceOfProp(Date).required,\n  },\n  computed: {\n    isoDate() {\n      return this.date.toISOString();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/layouts/default.vue",
    "content": "<template>\n  <div\n    id=\"ofl-root\"\n    :class=\"{\n      'js': isBrowser,\n      'no-js': !isBrowser,\n      'touch': isTouchScreen,\n      'no-touch': !isTouchScreen,\n    }\">\n\n    <a href=\"#content\" class=\"accessibility\">Skip to content</a>\n\n    <HeaderBar @focus-content=\"focusContent()\" />\n\n    <div id=\"content\" ref=\"content\" tabindex=\"-1\">\n      <ClimateStrikeBanner />\n      <Nuxt />\n    </div>\n\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.accessibility {\n  position: absolute;\n  top: -1000px;\n  left: -1000px;\n  z-index: 9999;\n  width: 1px;\n  height: 1px;\n  overflow: hidden;\n\n  &:active,\n  &:focus,\n  &:hover {\n    top: 0;\n    left: 0;\n    width: auto;\n    height: auto;\n    padding: 4px;\n    overflow: visible;\n    color: #ffffff;\n    background: red;\n  }\n}\n\n#content {\n  box-sizing: border-box;\n  max-width: 1000px;\n  min-height: 100vh;\n  padding: 5em 10px 10px;\n  margin: 0 auto;\n  overflow: hidden;\n\n  @media (max-width: $tablet) {\n    padding-top: 6.2em;\n  }\n}\n\n#content:focus {\n  outline: 0;\n}\n</style>\n\n<script>\nimport ClimateStrikeBanner from '../components/ClimateStrikeBanner.vue';\nimport HeaderBar from '../components/HeaderBar.vue';\n\nexport default {\n  components: {\n    HeaderBar,\n    ClimateStrikeBanner,\n  },\n  data() {\n    return {\n      isBrowser: false,\n      isTouchScreen: false,\n      lastTouchTime: 0,\n    };\n  },\n  mounted() {\n    this.isBrowser = true;\n\n    // adapted from https://stackoverflow.com/a/30303898/451391\n    document.addEventListener('touchstart', this.onTouchStart, true);\n    document.addEventListener('mousemove', this.onMouseMove, true);\n  },\n  beforeDestroy() {\n    document.removeEventListener('touchstart', this.onTouchStart, true);\n    document.removeEventListener('mousemove', this.onMouseMove, true);\n  },\n  methods: {\n    focusContent() {\n      this.$refs.content.focus();\n    },\n\n    onMouseMove() {\n      // filter emulated events coming from touch events\n      if (Date.now() - this.lastTouchTime < 500) {\n        return;\n      }\n\n      this.isTouchScreen = false;\n    },\n\n    onTouchStart() {\n      this.isTouchScreen = true;\n      this.lastTouchTime = Date.now();\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/layouts/error.vue",
    "content": "<template>\n  <div>\n    <template v-if=\"error.statusCode === 404\">\n      <h1>404 – Not found</h1>\n      <p>The requested page was not found. Maybe you've got the wrong URL? If not, consider <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues\">filing a bug</a>.</p>\n    </template>\n\n    <template v-else>\n      <h1>{{ error.statusCode }} – An error occurred</h1>\n\n      <p class=\"error\">{{ errorMessage }}</p>\n      <p>Please consider <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues\">filing a bug</a> to help resolve this issue.</p>\n    </template>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.error {\n  white-space: pre-wrap;\n}\n</style>\n\n<script>\nimport { oneOfTypesProp } from 'vue-ts-types';\n\nexport default {\n  props: {\n    error: oneOfTypesProp([Object, Error]).required,\n  },\n  head() {\n    if (this.error.statusCode !== 404) {\n      console.error('Nuxt rendering error:', this.error);\n    }\n\n    const title = this.error.statusCode === 404 ? 'Not Found' : 'Error';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n  computed: {\n    errorMessage() {\n      if (this.error.response && this.error.response.data && this.error.response.data.error) {\n        return this.error.response.data.error;\n      }\n\n      return this.error.message;\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/_manufacturerKey/_fixtureKey.vue",
    "content": "<template>\n  <div>\n    <FixtureHeader>\n      <template #title>\n        <h1>\n          <NuxtLink :to=\"`/${manufacturerKey}`\">{{ fixture.manufacturer.name }}</NuxtLink>\n          {{ fixture.name }}\n          <code v-if=\"fixture.hasShortName\">{{ fixture.shortName }}</code>\n        </h1>\n\n        <section class=\"fixture-meta\">\n          <span class=\"last-modify-date\">Last modified:&nbsp;<OflTime :date=\"fixture.meta.lastModifyDate\" /></span>\n          <span class=\"create-date\">Created:&nbsp;<OflTime :date=\"fixture.meta.createDate\" /></span>\n          <span class=\"authors\">Author{{ fixture.meta.authors.length === 1 ? `` : `s` }}:&nbsp;{{ fixture.meta.authors.join(`, `) }}</span>\n          <span class=\"source\"><a :href=\"`${githubRepoPath}/blob/${branch}/fixtures/${manufacturerKey}/${fixtureKey}.json`\">Source</a></span>\n          <span class=\"revisions\"><a :href=\"`${githubRepoPath}/commits/${branch}/fixtures/${manufacturerKey}/${fixtureKey}.json`\">Revisions</a></span>\n\n          <ConditionalDetails v-if=\"fixture.meta.importPlugin !== null\">\n            <template #summary>\n              Imported using the <NuxtLink :to=\"`/about/plugins/${fixture.meta.importPlugin}`\">{{ plugins.data[fixture.meta.importPlugin].name }} plugin</NuxtLink> on <OflTime :date=\"fixture.meta.importDate\" />.\n            </template>\n            <span v-if=\"fixture.meta.hasImportComment\">{{ fixture.meta.importComment }}</span>\n          </ConditionalDetails>\n        </section>\n      </template>\n\n      <DownloadButton :fixture-key=\"`${manufacturerKey}/${fixtureKey}`\" show-help />\n    </FixtureHeader>\n\n    <section v-if=\"redirect\" class=\"card yellow\">\n      Redirected from <code>{{ redirect.from }}</code>: {{ redirect.reason }}\n    </section>\n\n    <FixturePage\n      :fixture=\"fixture\"\n      :load-all-modes=\"`loadAllModes` in $route.query\"\n      @help-wanted-clicked=\"openHelpWantedDialog($event)\" />\n\n    <section id=\"contribute\">\n      <h2>Something wrong with this fixture definition?</h2>\n      <p>It does not work in your lighting software or you see another problem? Then please help correct it!</p>\n      <div class=\"grid-3\">\n        <a\n          v-if=\"isBrowser\"\n          href=\"#\"\n          class=\"card slim\"\n          @click.prevent=\"openHelpWantedDialog({\n            context: fixture,\n            type: `fixture`,\n          })\">\n          <OflSvg name=\"comment-alert\" class=\"left\" /><span>Send information</span>\n        </a>\n        <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues?q=is%3Aopen+is%3Aissue+label%3Abug\" rel=\"nofollow\" class=\"card slim\">\n          <OflSvg name=\"bug\" class=\"left\" /><span>Create issue on GitHub</span>\n        </a>\n        <a :href=\"mailtoUrl\" class=\"card slim\">\n          <OflSvg name=\"email\" class=\"left\" /><span>Send email</span>\n        </a>\n      </div>\n    </section>\n\n    <HelpWantedDialog v-model=\"helpWantedContext\" :type=\"helpWantedType\" />\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.fixture-meta {\n  margin: -1.5rem 0 1rem;\n  font-size: 0.8rem;\n  color: theme-color(text-secondary);\n\n  & > span:not(:last-child)::after {\n    padding: 0 0.7ex;\n    content: \" | \";\n  }\n}\n</style>\n\n<script>\nimport register from '../../../fixtures/register.json';\nimport Fixture from '../../../lib/model/Fixture.js';\nimport Manufacturer from '../../../lib/model/Manufacturer.js';\nimport ConditionalDetails from '../../components/ConditionalDetails.vue';\nimport DownloadButton from '../../components/DownloadButton.vue';\nimport FixturePage from '../../components/fixture-page/FixturePage.vue';\nimport FixtureHeader from '../../components/FixtureHeader.vue';\nimport HelpWantedDialog from '../../components/HelpWantedDialog.vue';\n\nconst redirectReasonExplanations = {\n  FixtureRenamed: 'The fixture was renamed.',\n  SameAsDifferentBrand: 'The fixture is the same but sold under different brands / names.',\n};\n\nexport default {\n  components: {\n    ConditionalDetails,\n    DownloadButton,\n    FixturePage,\n    FixtureHeader,\n    HelpWantedDialog,\n  },\n  validate({ params }) {\n    return `${params.manufacturerKey}/${params.fixtureKey}` in register.filesystem;\n  },\n  async asyncData({ params, query, $axios, redirect, error }) {\n    const { manufacturerKey, fixtureKey } = params;\n\n    const redirectTo = register.filesystem[`${manufacturerKey}/${fixtureKey}`].redirectTo;\n    if (redirectTo) {\n      return redirect(302, `/${redirectTo}?redirectFrom=${manufacturerKey}/${fixtureKey}`);\n    }\n\n    let fixtureJson;\n    let manufacturerJson;\n    let plugins;\n    let redirectObject;\n    try {\n      [fixtureJson, manufacturerJson, plugins, redirectObject] = await Promise.all([\n        $axios.$get(`/${manufacturerKey}/${fixtureKey}.json`),\n        $axios.$get(`/api/v1/manufacturers/${manufacturerKey}`),\n        $axios.$get('/api/v1/plugins'),\n        fetchRedirectObject($axios, query.redirectFrom),\n      ]);\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n\n    return {\n      plugins,\n      manufacturerKey,\n      manufacturerJson,\n      fixtureKey,\n      fixtureJson,\n      redirect: redirectObject,\n    };\n  },\n  data() {\n    return {\n      isBrowser: false,\n      helpWantedContext: undefined,\n      helpWantedType: '',\n    };\n  },\n  head() {\n    const title = `${this.fixture.manufacturer.name} ${this.fixture.name} DMX fixture definition`;\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n      script: [\n        {\n          hid: 'productModelStructuredData',\n          type: 'application/ld+json',\n          json: this.productModelStructuredData,\n        },\n        {\n          hid: 'breadcrumbListStructuredData',\n          type: 'application/ld+json',\n          json: this.breadcrumbListStructuredData,\n        },\n      ],\n    };\n  },\n  computed: {\n    fixture() {\n      const manufacturer = new Manufacturer(this.manufacturerKey, this.manufacturerJson);\n      return new Fixture(manufacturer, this.fixtureKey, this.fixtureJson);\n    },\n    productModelStructuredData() {\n      const data = {\n        '@context': 'https://schema.org',\n        '@type': 'ProductModel',\n        'name': this.fixture.name,\n        'category': this.fixture.mainCategory,\n        'manufacturer': {\n          url: `${this.$config.websiteUrl}${this.manufacturerKey}`,\n        },\n      };\n\n      if (this.fixture.hasComment) {\n        data.description = this.fixture.comment;\n      }\n\n      if (this.fixture.physical !== null && this.fixture.physical.dimensions !== null) {\n        data.depth = this.fixture.physical.depth;\n        data.width = this.fixture.physical.width;\n        data.height = this.fixture.physical.height;\n      }\n\n      return data;\n    },\n    breadcrumbListStructuredData() {\n      return {\n        '@context': 'https://schema.org',\n        '@type': 'BreadcrumbList',\n        'itemListElement': [\n          {\n            '@type': 'ListItem',\n            'position': 1,\n            'item': {\n              '@id': `${this.$config.websiteUrl}manufacturers`,\n              'name': 'Manufacturers',\n            },\n          },\n          {\n            '@type': 'ListItem',\n            'position': 2,\n            'item': {\n              '@id': `${this.$config.websiteUrl}${this.manufacturerKey}`,\n              'name': this.fixture.manufacturer.name,\n            },\n          },\n          {\n            '@type': 'ListItem',\n            'position': 3,\n            'item': {\n              '@id': this.fixture.url,\n              'name': this.fixture.name,\n            },\n          },\n        ],\n      };\n    },\n    githubRepoPath() {\n      const slug = process.env.GITHUB_REPOSITORY || 'OpenLightingProject/open-fixture-library';\n      return `https://github.com/${slug}`;\n    },\n    branch() {\n      const gitRef = process.env.GITHUB_PR_BASE_REF || process.env.GITHUB_REF || 'master';\n      // e.g. for `refs/heads/feature-branch-1`, return `feature-branch-1`\n      return gitRef.split('/').pop();\n    },\n    mailtoUrl() {\n      const subject = `Feedback for fixture '${this.manufacturerKey}/${this.fixtureKey}'`;\n      return `mailto:flo@open-fixture-library.org?subject=${encodeURIComponent(subject)}`;\n    },\n  },\n  mounted() {\n    this.isBrowser = true;\n  },\n  methods: {\n    openHelpWantedDialog(event) {\n      this.helpWantedContext = event.context;\n      this.helpWantedType = event.type;\n    },\n  },\n};\n\n/**\n * @param {object} axios The Axios instance.\n * @param {string | undefined} redirectFrom The query parameter with the original request's fixture key.\n * @returns {object} The redirect object.\n */\nasync function fetchRedirectObject(axios, redirectFrom) {\n  if (!redirectFrom) {\n    return undefined;\n  }\n\n  const redirectJson = await axios.$get(`/${redirectFrom}.json`);\n\n  return {\n    from: redirectFrom,\n    reason: redirectReasonExplanations[redirectJson.reason],\n  };\n}\n</script>\n"
  },
  {
    "path": "ui/pages/_manufacturerKey/index.vue",
    "content": "<template>\n  <div>\n    <h1>{{ manufacturer.name }} fixtures</h1>\n\n    <div v-if=\"`website` in manufacturer || `rdmId` in manufacturer\" class=\"grid-3\">\n      <a\n        v-if=\"`website` in manufacturer\"\n        :href=\"manufacturer.website\"\n        class=\"card slim blue dark\">\n        <OflSvg name=\"web\" class=\"left\" />\n        <span>Manufacturer website</span>\n      </a>\n      <a\n        v-if=\"`rdmId` in manufacturer\"\n        :href=\"`http://rdm.openlighting.org/manufacturer/display?manufacturer=${manufacturer.rdmId}`\"\n        rel=\"nofollow\"\n        class=\"card slim\">\n        <OflSvg name=\"ola\" class=\"left\" />\n        <span>Open Lighting RDM database</span>\n      </a>\n    </div>\n\n    <p v-if=\"`comment` in manufacturer\" class=\"comment\" style=\"white-space: pre-wrap;\">{{ manufacturer.comment }}</p>\n\n    <div class=\"card\">\n      <ul class=\"list fixtures\">\n        <li v-for=\"fixture of fixtures\" :key=\"fixture.key\">\n          <NuxtLink\n            :to=\"`/${manufacturer.key}/${fixture.key}`\"\n            :style=\"{ borderLeftColor: manufacturer.color }\"\n            class=\"manufacturer-color\">\n            <span class=\"name\">{{ fixture.name }}</span>\n            <OflSvg\n              v-for=\"cat of fixture.categories\"\n              :key=\"cat\"\n              :name=\"cat\"\n              type=\"fixture\"\n              class=\"right inactive\" />\n          </NuxtLink>\n        </li>\n      </ul>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  async asyncData({ params, $axios, error }) {\n    let manufacturer;\n    try {\n      manufacturer = await $axios.$get(`/api/v1/manufacturers/${params.manufacturerKey}`);\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n    return { manufacturer };\n  },\n  head() {\n    const title = this.manufacturer.name;\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n      script: [\n        {\n          hid: 'organizationStructuredData',\n          type: 'application/ld+json',\n          json: this.organizationStructuredData,\n        },\n        {\n          hid: 'itemListStructuredData',\n          type: 'application/ld+json',\n          json: this.itemListStructuredData,\n        },\n      ],\n    };\n  },\n  computed: {\n    fixtures() {\n      return this.manufacturer.fixtures;\n    },\n    organizationStructuredData() {\n      return {\n        '@context': 'https://schema.org',\n        '@type': 'Organization',\n        'name': this.manufacturer.name,\n        'brand': this.manufacturer.name,\n        'sameAs': 'website' in this.manufacturer ? this.manufacturer.website : undefined,\n      };\n    },\n    itemListStructuredData() {\n      return {\n        '@context': 'https://schema.org',\n        '@type': 'ItemList',\n        'itemListElement': this.fixtures.map((fixture, index) => ({\n          '@type': 'ListItem',\n          'position': index + 1,\n          'url': `${this.$config.websiteUrl}${this.manufacturer.key}/${fixture.key}`,\n        })),\n      };\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/about/index.vue",
    "content": "<template>\n  <div>\n    <h1>About</h1>\n\n    <p>Created by Florian and Felix Edelmann.</p>\n    <p>The full code of the <em>Open Fixture Library</em> is <a href=\"https://github.com/OpenLightingProject/open-fixture-library\">open source</a> (licensed under the <a href=\"https://www.tldrlegal.com/license/mit-license\" title=\"Massachusetts Institute of Technology License\">MIT License</a>) and everybody is invited to contribute!</p>\n\n    <h2>Documentation</h2>\n    <p>The developer documentation can be found at the <a href=\"https://github.com/OpenLightingProject/open-fixture-library/tree/master/docs\">GitHub repository</a>. It contains an explanation of the <a href=\"https://github.com/OpenLightingProject/open-fixture-library/blob/master/docs/fixture-format.md\">JSON fixture format</a> we use internally, and from which fixture definitions in other formats can be exported by <a href=\"https://github.com/OpenLightingProject/open-fixture-library/blob/master/docs/plugins.md\">plugins</a>.</p>\n\n    <h2>History</h2>\n    <p>We were used to programming lighting shows with the <a href=\"https://www.osram.de/ecue/\">e:cue</a> software and – because at some point we found it being limited in functionality – wanted to try out other programs. I built a <a href=\"https://github.com/FloEdelmann/bachelor\">DMX interface</a> with <a href=\"https://www.openlighting.org/ola/\">Open Lighting Architecture</a> to be able to try <a href=\"https://www.qlcplus.org/\">QLC+</a> and we kept on using that combination since then.</p>\n    <p>The problem we noticed during our testing phase was that all the fixture definitions we created for e:cue could not be easily converted for use with other software. The idea for a converter was born (<a href=\"https://github.com/FloEdelmann/fixture-converter\">fixture-converter on GitHub</a>, September 2016 – January 2017).</p>\n    <p>Since we wanted our work to be as useful for other people as possible, we decided to build a website that would store the fixtures in a wiki-like way (everybody can help improve it) and allow auto-generated fixture files in various formats to be downloaded. Creating new fixtures should be made as simple as possible with an online <a href=\"/fixture-editor\">Fixture Editor</a> that could also import from existing fixture definitions. For roughly a year (February 2017 – March 2018), the site kept getting better and better at <i>open-fixture-library.herokuapp.com</i>.</p>\n    <p>In March 2018, we decided it was time to get our own server and domain – and at the same time were invited to the <a href=\"https://github.com/OpenLightingProject\">Open Lighting Project</a> (see <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues/453\">issue #453</a> on GitHub), so here we are \"under the new flag\" at <a href=\"https://open-fixture-library.org\">open-fixture-library.org</a>! Of course there is still more to be improved, so feel free to contribute!</p>\n\n    <h2>Used resources</h2>\n    <p>\n      Fonts: <a href=\"https://www.latofonts.com/\">Lato</a> and <a href=\"https://levien.com/type/myfonts/inconsolata.html\" class=\"monospaced\">Inconsolata</a><br>\n      Icons: <a href=\"https://pictogrammers.com/library/mdi/\">Material Design Icons</a>\n    </p>\n\n    <h2>Contribute</h2>\n    <p>See the <a href=\"https://github.com/OpenLightingProject/open-fixture-library#contribute\">project page on GitHub</a> to see how you can help.</p>\n\n    <h2 id=\"contact\">Contact</h2>\n    <p><a href=\"mailto:flo@open-fixture-library.org\">flo@open-fixture-library.org</a> or via <a href=\"https://github.com/FloEdelmann\">GitHub</a></p>\n\n    <h2>Privacy</h2>\n    <p>We respect users' privacy and thus collect as few data as possible. No personal data about our visitors is stored on our server or sent to other sites without users' consent. The communication between users' browsers and our server is encrypted via HTTPS. Videos are embetted with <a href=\"https://github.com/heiseonline/embetty\">embetty</a>, so no information is sent from users' browsers to the video hosting platform (e.g. YouTube) until the video is played. The fixture editor only uses the entered data to open a pull request in our public GitHub repository; this means that the chosen author name and GitHub username – the only personal data – will be made public. Unfinished fixtures and the last submitted author name / GitHub username are saved locally in users' browsers. Other technical measures to improve privacy and security <a href=\"https://developer.mozilla.org/en-US/observatory/analyze?host=open-fixture-library.org\">are implemented</a>.</p>\n\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\np {\n  text-align: justify;\n}\n\nh2 {\n  margin: 1.5rem 0 -0.5rem;\n  line-height: 1.3;\n}\n\n.monospaced {\n  font-family: $font-stack-code;\n  font-weight: 400;\n}\n</style>\n\n<script>\nexport default {\n  head() {\n    const title = 'About';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/about/plugins/_plugin.vue",
    "content": "<template>\n  <div>\n    <h1>{{ pluginData.name }} Plugin</h1>\n\n    <div class=\"version-info hint\">\n      <template v-if=\"exportPluginVersion\">Export plugin version {{ exportPluginVersion }}</template>\n      <template v-if=\"exportPluginVersion && importPluginVersion\"> | </template>\n      <template v-if=\"importPluginVersion\">Import plugin version {{ importPluginVersion }}</template>\n    </div>\n\n    <!-- eslint-disable-next-line vue/no-v-html -->\n    <div class=\"plugin-description\" v-html=\"pluginData.description\" />\n\n    <ul>\n      <li v-for=\"link of Object.keys(pluginData.links)\" :key=\"link\">\n        <a :href=\"pluginData.links[link]\" target=\"_blank\" rel=\"nofollow noopener\">{{ link }}</a>\n      </li>\n    </ul>\n\n    <HelpWantedMessage\n      v-if=\"`helpWanted` in pluginData\"\n      type=\"plugin\"\n      :context=\"pluginData\"\n      @help-wanted-clicked=\"openHelpWantedDialog($event)\" />\n\n    <div v-if=\"`fixtureUsage` in pluginData\" class=\"fixture-usage\">\n      <h2 id=\"fixture-usage\">Install fixture definitions</h2>\n\n      <p><NuxtLink to=\"/manufacturers\">Browse to the fixture</NuxtLink> you want to download, then select <em>{{ pluginData.name }}</em> in the <em>Download as…</em> button.</p>\n\n      <!-- eslint-disable-next-line vue/no-v-html -->\n      <div v-html=\"pluginData.fixtureUsage\" />\n    </div>\n\n    <div v-if=\"`fileLocations` in pluginData\" class=\"file-locations\">\n      <h2>File locations</h2>\n\n      <p v-if=\"`subDirectoriesAllowed` in pluginData.fileLocations\">\n        Fixture files in subdirectories are {{ pluginData.fileLocations.subDirectoriesAllowed ? `recognized` : `not recognized` }}.\n      </p>\n\n      <div v-for=\"os of fileLocationOSes\" :key=\"os\">\n        <h3>{{ os }}</h3>\n\n        <section>\n          <div v-for=\"library of Object.keys(pluginData.fileLocations[os])\" :key=\"`${os}-${library}`\">\n            {{ libraryNames[library] }}: <code>{{ pluginData.fileLocations[os][library] }}</code>\n          </div>\n        </section>\n      </div>\n    </div>\n\n    <div v-if=\"`additionalInfo` in pluginData\" class=\"additional-info\">\n      <h2>Additional information</h2>\n\n      <!-- eslint-disable-next-line vue/no-v-html -->\n      <div v-html=\"pluginData.additionalInfo\" />\n    </div>\n\n    <p style=\"margin-top: 3rem;\"><NuxtLink to=\"/about/plugins\">Back to plugin overview</NuxtLink></p>\n\n    <HelpWantedDialog v-model=\"helpWantedContext\" type=\"plugin\" />\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.version-info {\n  margin: -1rem 0 0;\n}\n\n.plugin-description,\n.fixture-usage,\n.file-locations,\n.additional-info {\n  & ::v-deep h2,\n  & ::v-deep h3 {\n    margin: 1.5rem 0 -0.5rem;\n    line-height: 1.3;\n  }\n\n  & ::v-deep p {\n    text-align: justify;\n  }\n\n  & ::v-deep code {\n    padding: 3px 5px;\n    background-color: theme-color(header-background);\n  }\n\n  & ::v-deep table {\n    margin: 1rem 0;\n    border-collapse: collapse;\n    border: 1px solid theme-color(divider);\n\n    th,\n    td {\n      padding: 1px 1ex;\n      border: 1px solid theme-color(divider);\n    }\n  }\n}\n</style>\n\n<script>\nimport HelpWantedDialog from '../../../components/HelpWantedDialog.vue';\nimport HelpWantedMessage from '../../../components/HelpWantedMessage.vue';\n\nexport default {\n  components: {\n    HelpWantedDialog,\n    HelpWantedMessage,\n  },\n  async asyncData({ params, $axios, redirect, error }) {\n    const pluginKey = params.plugin;\n    let pluginData;\n    try {\n      pluginData = await $axios.$get(`/api/v1/plugins/${pluginKey}`);\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n\n    if (pluginKey in pluginData.previousVersions) {\n      const newPluginKey = pluginData.key;\n      return redirect(301, `/about/plugins/${newPluginKey}`);\n    }\n\n    return { pluginData };\n  },\n  data() {\n    return {\n      helpWantedContext: undefined,\n      libraryNames: {\n        main: 'Main (system) library',\n        user: 'User library',\n      },\n    };\n  },\n  head() {\n    const title = `${this.pluginData.name} Plugin`;\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n  computed: {\n    exportPluginVersion() {\n      return this.pluginData.exportPluginVersion;\n    },\n    importPluginVersion() {\n      return this.pluginData.importPluginVersion;\n    },\n    fileLocationOSes() {\n      return 'fileLocations' in this.pluginData\n        ? Object.keys(this.pluginData.fileLocations).filter(\n            (os) => os !== 'subDirectoriesAllowed',\n          )\n        : null;\n    },\n  },\n  methods: {\n    openHelpWantedDialog(event) {\n      this.helpWantedContext = event.context;\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/about/plugins/index.vue",
    "content": "<template>\n  <div>\n    <h1>Plugins</h1>\n\n    <p>A plugin in <abbr title=\"Open Fixture Library\">OFL</abbr> is a converter between our <a href=\"https://github.com/OpenLightingProject/open-fixture-library/blob/master/docs/fixture-format.md\">internal fixture definition format</a> and an external format used by DMX lighting software or desks. Click on one of the plugins below to learn more about the corresponding fixture format and download instructions.</p>\n\n    <div class=\"grid-3 centered\">\n      <div class=\"card\">\n        <h2>Export plugins</h2>\n\n        <div class=\"hint\">for downloading OFL fixtures in various formats</div>\n\n        <ul class=\"list\">\n          <li v-for=\"plugin of plugins.exportPlugins\" :key=\"plugin\">\n            <NuxtLink :to=\"`/about/plugins/${plugin}`\">\n              <OflSvg name=\"puzzle\" class=\"left\" />\n              <span class=\"name\">{{ plugins.data[plugin].name }}</span>\n            </NuxtLink>\n          </li>\n        </ul>\n      </div>\n\n      <div class=\"card\">\n        <h2>Import plugins</h2>\n\n        <div class=\"hint\">for <NuxtLink to=\"/import-fixture-file\">importing fixtures</NuxtLink> from other formats into OFL</div>\n\n        <ul class=\"list\">\n          <li v-for=\"plugin of plugins.importPlugins\" :key=\"plugin\">\n            <NuxtLink :to=\"`/about/plugins/${plugin}`\">\n              <OflSvg name=\"puzzle\" class=\"left\" />\n              <span class=\"name\">{{ plugins.data[plugin].name }}</span>\n            </NuxtLink>\n          </li>\n        </ul>\n      </div>\n    </div>\n\n    <h3>New plugins</h3>\n\n    <p>If your desired import or export format is not yet supported, please see if there is already an <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Anew-plugin\" rel=\"nofollow\">open issue</a> for it in the GitHub repository. If so, try to add information there. Otherwise, please open a <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues/new?assignees=&amp;labels=new-plugin&amp;template=new-plugin.md&amp;title=Add+%5Bsoftware+%2F+console+name%5D+Plugin\" rel=\"nofollow\">new issue</a>.</p>\n\n    <p>Useful information for developers: <a href=\"https://github.com/OpenLightingProject/open-fixture-library/blob/master/docs/plugins.md\">Plugin documentation</a></p>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.hint {\n  margin-bottom: 1rem;\n}\n\nh3 {\n  margin: 1.5rem 0 -0.5rem;\n  line-height: 1.3;\n}\n</style>\n\n<script>\nexport default {\n  async asyncData({ $axios, error }) {\n    let plugins;\n    try {\n      plugins = await $axios.$get('/api/v1/plugins');\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n    return { plugins };\n  },\n  head() {\n    const title = 'Plugins';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/categories/_category.vue",
    "content": "<template>\n  <div>\n    <h1>{{ categoryName }} fixtures</h1>\n\n    <div class=\"card\">\n      <ul class=\"list fixtures\" :class=\"`category-${categoryClass}`\">\n        <li v-for=\"fixture of fixtures\" :key=\"fixture.key\">\n          <NuxtLink\n            :to=\"fixture.link\"\n            :style=\"{ borderLeftColor: fixture.color }\"\n            class=\"manufacturer-color\">\n            <span class=\"name\">{{ fixture.name }}</span>\n            <OflSvg\n              v-for=\"cat of fixture.categories\"\n              :key=\"cat\"\n              :name=\"cat\"\n              class=\"right\"\n              :class=\"{ inactive: cat !== categoryName }\"\n              type=\"fixture\" />\n          </NuxtLink>\n        </li>\n      </ul>\n    </div>\n  </div>\n</template>\n\n<script>\nimport register from '../../../fixtures/register.json';\n\nexport default {\n  validate({ params }) {\n    return decodeURIComponent(params.category) in register.categories;\n  },\n  async asyncData({ $axios, error }) {\n    let manufacturers;\n    try {\n      manufacturers = await $axios.$get('/api/v1/manufacturers');\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n    return { manufacturers };\n  },\n  head() {\n    const title = this.categoryName;\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n  computed: {\n    categoryName() {\n      return this.$route.params.category;\n    },\n    categoryClass() {\n      return this.categoryName.toLowerCase().replaceAll(/\\W+/g, '-');\n    },\n    fixtures() {\n      return register.categories[this.categoryName].map((fullFixtureKey) => {\n        const [manufacturerKey, fixtureKey] = fullFixtureKey.split('/');\n        const manufacturerName = this.manufacturers[manufacturerKey].name;\n        const fixtureName = register.filesystem[`${manufacturerKey}/${fixtureKey}`].name;\n\n        return {\n          key: fullFixtureKey,\n          link: `/${fullFixtureKey}`,\n          name: `${manufacturerName} ${fixtureName}`,\n          categories: Object.keys(register.categories).filter(\n            (category) => register.categories[category].includes(fullFixtureKey),\n          ),\n          color: this.manufacturers[manufacturerKey].color,\n        };\n      });\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/categories/index.vue",
    "content": "<template>\n  <div>\n    <h1>Categories</h1>\n\n    <div class=\"categories grid-3\">\n      <NuxtLink\n        v-for=\"category of categories\"\n        :key=\"category.name\"\n        :to=\"`/categories/${encodeURIComponent(category.name)}`\"\n        class=\"card card-category\">\n        <OflSvg :name=\"category.name\" type=\"fixture\" />\n        <h2>{{ category.name }}</h2>\n        <div class=\"fixtures\">{{ category.fixtureCount }} fixture{{ category.fixtureCount === 1 ? `` : `s` }}</div>\n      </NuxtLink>\n    </div>\n  </div>\n</template>\n\n<script>\nimport register from '../../../fixtures/register.json';\n\nexport default {\n  data() {\n    return {\n      categories: Object.keys(register.categories).toSorted((a, b) => a.localeCompare(b, 'en')).map(\n        (category) => ({\n          name: category,\n          fixtureCount: register.categories[category].length,\n        }),\n      ),\n    };\n  },\n  head() {\n    const title = 'Categories';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/fixture-editor.vue",
    "content": "<template>\n  <div id=\"fixture-editor\">\n    <h1>Fixture Editor</h1>\n\n    <section class=\"card\">\n      <h2>Import fixture</h2>\n      Instead of creating a new fixture definition in the editor below, you can also <NuxtLink to=\"/import-fixture-file\">import an existing fixture definition file</NuxtLink>.\n    </section>\n\n    <noscript class=\"card yellow\">\n      Please enable JavaScript to use the Fixture Editor!\n    </noscript>\n\n    <ClientOnly placeholder=\"Fixture editor is loading...\">\n\n      <VueForm\n        :state=\"formstate\"\n        action=\"#\"\n        class=\"only-js\"\n        @submit.prevent=\"onSubmit()\">\n\n        <EditorManufacturer\n          :fixture=\"fixture\"\n          :formstate=\"formstate\"\n          :manufacturers=\"manufacturers\" />\n\n        <EditorFixtureInformation\n          :fixture=\"fixture\"\n          :formstate=\"formstate\"\n          :manufacturers=\"manufacturers\" />\n\n        <section class=\"physical card\">\n          <h2>Physical data</h2>\n          <EditorPhysical\n            v-model=\"fixture.physical\"\n            :formstate=\"formstate\"\n            name-prefix=\"fixture\" />\n        </section>\n\n        <section class=\"fixture-modes\">\n          <EditorMode\n            v-for=\"(mode, index) of fixture.modes\"\n            :key=\"mode.uuid\"\n            :mode=\"fixture.modes[index]\"\n            :index=\"index\"\n            :fixture=\"fixture\"\n            :formstate=\"formstate\"\n            @open-channel-editor=\"openChannelEditor($event)\"\n            @remove=\"fixture.modes.splice(index, 1)\" />\n\n          <a class=\"fixture-mode card add-mode-link\" href=\"#add-mode\" @click.prevent=\"addNewMode()\">\n            <h2>+ Add mode</h2>\n          </a>\n\n          <div class=\"clearfix\" />\n        </section>\n\n        <section class=\"user card\">\n          <h2>Author data</h2>\n\n          <LabeledInput :formstate=\"formstate\" name=\"author\" label=\"Your name\">\n            <PropertyInputText\n              v-model=\"fixture.metaAuthor\"\n              :schema-property=\"schemaDefinitions.nonEmptyString\"\n              required\n              name=\"author\"\n              hint=\"e.g. Anonymous\" />\n          </LabeledInput>\n\n          <LabeledInput\n            :formstate=\"formstate\"\n            name=\"github-username\"\n            label=\"GitHub username\"\n            hint=\"If you want to be mentioned in the pull request.\">\n            <PropertyInputText\n              v-model=\"githubUsername\"\n              :schema-property=\"schemaDefinitions.nonEmptyString\"\n              name=\"github-username\" />\n          </LabeledInput>\n\n          <LabeledInput hidden name=\"honeypot\" label=\"Ignore this!\">\n            <input v-model=\"honeypot\" type=\"text\">\n            <div class=\"hint\">Spammers are likely to fill this field. Leave it empty to show that you're a human.</div>\n          </LabeledInput>\n        </section>\n\n        <div class=\"button-bar right\">\n          <button type=\"submit\" class=\"save-fixture primary\">Create fixture</button>\n        </div>\n\n      </VueForm>\n\n      <EditorChannelDialog\n        :channel=\"channel\"\n        :fixture=\"fixture\"\n        @reset-channel=\"resetChannel()\"\n        @channel-changed=\"autoSave(`channel`)\"\n        @remove-channel=\"removeChannel($event)\" />\n\n      <EditorChooseChannelEditModeDialog\n        :channel=\"channel\"\n        :fixture=\"fixture\" />\n\n      <EditorRestoreDialog v-model=\"restoredData\" @restore-complete=\"restoreComplete()\" />\n\n      <EditorSubmitDialog\n        ref=\"submitDialog\"\n        endpoint=\"/api/v1/fixtures/from-editor\"\n        :github-username=\"githubUsername\"\n        @success=\"onFixtureSubmitted()\"\n        @reset=\"reset()\" />\n\n    </ClientOnly>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.add-mode-link {\n  text-align: center;\n}\n\nnoscript.card {\n  display: block;\n  margin-top: 1rem;\n}\n</style>\n\n<script>\nimport scrollIntoView from 'scroll-into-view';\nimport { schemaDefinitions } from '../../lib/schema-properties.js';\nimport {\n  constants,\n  getEmptyChannel,\n  getEmptyFixture,\n  getEmptyFormState,\n  getEmptyMode,\n} from '../assets/scripts/editor-utilities.js';\nimport EditorChannelDialog from '../components/editor/EditorChannelDialog.vue';\nimport EditorChooseChannelEditModeDialog from '../components/editor/EditorChooseChannelEditModeDialog.vue';\nimport EditorFixtureInformation from '../components/editor/EditorFixtureInformation.vue';\nimport EditorManufacturer from '../components/editor/EditorManufacturer.vue';\nimport EditorMode from '../components/editor/EditorMode.vue';\nimport EditorPhysical from '../components/editor/EditorPhysical.vue';\nimport EditorRestoreDialog from '../components/editor/EditorRestoreDialog.vue';\nimport EditorSubmitDialog from '../components/editor/EditorSubmitDialog.vue';\nimport LabeledInput from '../components/LabeledInput.vue';\nimport PropertyInputText from '../components/PropertyInputText.vue';\n\nexport default {\n  components: {\n    EditorChannelDialog,\n    EditorChooseChannelEditModeDialog,\n    EditorFixtureInformation,\n    EditorManufacturer,\n    EditorMode,\n    EditorPhysical,\n    EditorRestoreDialog,\n    EditorSubmitDialog,\n    LabeledInput,\n    PropertyInputText,\n  },\n  async asyncData({ $axios, error }) {\n    let manufacturers;\n    try {\n      manufacturers = await $axios.$get('/api/v1/manufacturers');\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n    return { manufacturers };\n  },\n  data() {\n    return {\n      formstate: getEmptyFormState(),\n      readyToAutoSave: false,\n      restoredData: undefined,\n      fixture: getEmptyFixture(),\n      channel: getEmptyChannel(),\n      githubUsername: '',\n      honeypot: '',\n      schemaDefinitions,\n    };\n  },\n  head() {\n    const title = 'Fixture Editor';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n  watch: {\n    fixture: {\n      handler() {\n        this.autoSave('fixture');\n      },\n      deep: true,\n    },\n  },\n  beforeMount() {\n    this.$root._oflRestoreComplete = false;\n  },\n  async mounted() {\n    this.applyQueryPrefillData();\n    this.applyStoredPrefillData();\n\n    // let all components initialize without auto-focus\n    await this.$nextTick();\n\n    this.restoreAutoSave();\n  },\n  methods: {\n    addNewMode() {\n      this.fixture.modes.push(getEmptyMode());\n    },\n\n    openChannelEditor(channelData) {\n      this.channel = { ...this.channel, ...channelData };\n    },\n\n    resetChannel() {\n      this.channel = getEmptyChannel();\n    },\n\n    /**\n     * @param {string} channelUuid The channel's UUID.\n     * @returns {string} The channel's name.\n     */\n    getChannelName(channelUuid) {\n      const channel = this.fixture.availableChannels[channelUuid];\n\n      if ('coarseChannelId' in channel) {\n        let name = `${this.getChannelName(channel.coarseChannelId)} fine`;\n        if (channel.resolution > constants.RESOLUTION_16BIT) {\n          name += `^${channel.resolution - 1}`;\n        }\n\n        return name;\n      }\n\n      return channel.name;\n    },\n\n    /**\n     * Called from {@link EditorMode}.\n     * @public\n     * @param {string} channelUuid The channel's UUID.\n     * @returns {boolean} True if the channel's name is not used in another channel, too.\n     */\n    isChannelNameUnique(channelUuid) {\n      const channelName = this.getChannelName(channelUuid);\n\n      return Object.keys(this.fixture.availableChannels).every(\n        (uuid) => channelName !== this.getChannelName(uuid) || uuid === channelUuid,\n      );\n    },\n\n    /**\n     * @param {string} channelUuid The channel's UUID.\n     * @param {string | null} [modeUuid] The mode's UUID. If not supplied, remove channel everywhere.\n     */\n    removeChannel(channelUuid, modeUuid) {\n      if (modeUuid) {\n        const channelMode = this.fixture.modes.find((mode) => mode.uuid === modeUuid);\n\n        const channelPosition = channelMode.channels.indexOf(channelUuid);\n        if (channelPosition !== -1) {\n          // remove channel reference from mode\n          channelMode.channels.splice(channelPosition, 1);\n        }\n\n        return;\n      }\n\n      // remove fine channels first\n      for (const channel of Object.values(this.fixture.availableChannels)) {\n        if ('coarseChannelId' in channel && channel.coarseChannelId === channelUuid) {\n          this.removeChannel(channel.uuid);\n        }\n      }\n\n      // now remove all references from modes\n      for (const mode of this.fixture.modes) {\n        this.removeChannel(channelUuid, mode.uuid);\n      }\n\n      // finally remove the channel itself\n      delete this.fixture.availableChannels[channelUuid];\n    },\n\n    /**\n     * Saves the entered user data to the browser's local storage if available.\n     * @param {'fixture' | 'channel'} objectName The object to save.\n     */\n    autoSave(objectName) {\n      if (!this.readyToAutoSave) {\n        return;\n      }\n\n      if (objectName === 'fixture') {\n        console.log('autoSave fixture:', JSON.parse(JSON.stringify(this.fixture, null, 2)));\n      }\n      else if (objectName === 'channel') {\n        console.log('autoSave channel:', JSON.parse(JSON.stringify(this.channel, null, 2)));\n      }\n\n      // use an array to be future-proof (maybe we want to support multiple browser tabs sometime)\n      localStorage.setItem('autoSave', JSON.stringify([\n        {\n          fixture: this.fixture,\n          channel: this.channel,\n          timestamp: Date.now(),\n        },\n      ]));\n    },\n\n    clearAutoSave() {\n      localStorage.removeItem('autoSave');\n    },\n\n    /**\n     * Loads auto-saved data from browser's local storage into this component's `restoredData` property, such that a dialog is opened that lets the user choose if they want to apply or discard it.\n     */\n    restoreAutoSave() {\n      try {\n        this.restoredData = JSON.parse(localStorage.getItem('autoSave')).pop();\n\n        if (this.restoredData === undefined) {\n          throw new Error('this.restoredData is undefined.');\n        }\n      }\n      catch {\n        this.restoredData = undefined;\n        this.restoreComplete();\n        return;\n      }\n\n      console.log('restore', structuredClone(this.restoredData));\n    },\n\n    /**\n     * Called from restore dialog (via an event) after the restored data are either applied or discarded.\n     */\n    restoreComplete() {\n      this.readyToAutoSave = true;\n      this.$root._oflRestoreComplete = true;\n      window.scrollTo(0, 0);\n    },\n\n    applyQueryPrefillData() {\n      if (!this.$route.query.prefill) {\n        return;\n      }\n\n      try {\n        const prefillObject = JSON.parse(this.$route.query.prefill);\n        for (const key of Object.keys(prefillObject)) {\n          if (isPrefillable(prefillObject, key)) {\n            this.fixture[key] = prefillObject[key];\n          }\n        }\n      }\n      catch (parseError) {\n        console.log('prefill query could not be parsed:', this.$route.query.prefill, parseError);\n      }\n    },\n\n    applyStoredPrefillData() {\n      if (this.fixture.metaAuthor === '') {\n        this.fixture.metaAuthor = localStorage.getItem('prefillAuthor') || '';\n      }\n\n      if (this.githubUsername === '') {\n        this.githubUsername = localStorage.getItem('prefillGithubUsername') || '';\n      }\n    },\n\n    storePrefillData() {\n      localStorage.setItem('prefillAuthor', this.fixture.metaAuthor);\n      localStorage.setItem('prefillGithubUsername', this.githubUsername);\n    },\n\n    onSubmit() {\n      if (this.formstate.$invalid) {\n        const field = document.querySelector('.vf-field-invalid');\n\n        scrollIntoView(field, {\n          time: 300,\n          align: {\n            top: 0,\n            left: 0,\n            topOffset: 100,\n          },\n          isScrollable: (target) => target === window,\n        }, () => field.focus());\n\n        return;\n      }\n\n      if (this.honeypot !== '') {\n        alert('Do not fill the \"Ignore\" fields!');\n        return;\n      }\n\n      this.$refs.submitDialog.validate([this.fixture]);\n    },\n\n    onFixtureSubmitted() {\n      this.storePrefillData();\n      this.clearAutoSave();\n    },\n\n    async reset() {\n      this.fixture = getEmptyFixture();\n      this.channel = getEmptyChannel();\n      this.honeypot = '';\n      this.applyStoredPrefillData();\n\n      this.$router.push({\n        path: this.$route.path,\n        query: {}, // clear prefill query\n      });\n\n      await this.$nextTick();\n\n      this.formstate._reset();\n      this.$refs.existingManufacturerSelect.focus();\n      window.scrollTo(0, 0);\n    },\n  },\n};\n\n/**\n * @param {object} prefillObject The object supplied in the page query.\n * @param {string} key The key to check.\n * @returns {boolean} True if the value prefillObject[key] is prefillable, false otherwise.\n */\nfunction isPrefillable(prefillObject, key) {\n  const allowedPrefillValues = {\n    useExistingManufacturer: 'boolean',\n    manufacturerKey: 'string',\n    newManufacturerRdmId: 'number',\n    rdmModelId: 'number',\n  };\n\n  return key in allowedPrefillValues && typeof prefillObject[key] === allowedPrefillValues[key];\n}\n</script>\n"
  },
  {
    "path": "ui/pages/import-fixture-file.vue",
    "content": "<template>\n  <div>\n    <h1>Import fixture file</h1>\n\n    <section class=\"card yellow\">\n      <strong>Warning:</strong> The fixture can not be edited after importing, so please provide as much information as possible in the comment.\n    </section>\n\n    <noscript class=\"card yellow\">\n      Please enable JavaScript to use the Fixture Importer!\n    </noscript>\n\n    <ClientOnly placeholder=\"Fixture Importer is loading...\">\n\n      <VueForm\n        :state=\"formstate\"\n        action=\"#\"\n        class=\"only-js\"\n        @submit.prevent=\"onSubmit()\">\n\n        <section class=\"card\">\n          <h2>File information</h2>\n\n          <LabeledInput :formstate=\"formstate\" name=\"plugin\" label=\"Import file type\">\n            <select\n              v-model=\"plugin\"\n              :class=\"{ empty: plugin === `` }\"\n              required\n              name=\"plugin\">\n\n              <option value=\"\" disabled>Please select an import file type</option>\n\n              <template v-for=\"pluginKey of plugins.importPlugins\">\n                <option :key=\"pluginKey\" :value=\"pluginKey\">\n                  {{ plugins.data[pluginKey].name }}\n                </option>\n              </template>\n\n            </select>\n\n            <div class=\"hint\">See <a href=\"/about/plugins\" target=\"_blank\">supported import plugins</a>.</div>\n          </LabeledInput>\n\n          <LabeledInput\n            :formstate=\"formstate\"\n            name=\"file\"\n            label=\"Fixture definition file\"\n            hint=\"Maximum file size is 50MB.\">\n            <EditorFileUpload\n              v-model=\"file\"\n              required\n              name=\"file\"\n              max-file-size=\"50MB\" />\n          </LabeledInput>\n\n          <LabeledInput :formstate=\"formstate\" name=\"githubComment\" label=\"Comment\">\n            <textarea v-model=\"githubComment\" name=\"githubComment\" />\n          </LabeledInput>\n        </section>\n\n        <section class=\"user card\">\n          <h2>Author data</h2>\n\n          <LabeledInput :formstate=\"formstate\" name=\"author\" label=\"Your name\">\n            <input\n              v-model=\"author\"\n              type=\"text\"\n              required\n              name=\"author\"\n              placeholder=\"e.g. Anonymous\">\n          </LabeledInput>\n\n          <LabeledInput\n            :formstate=\"formstate\"\n            name=\"githubUsername\"\n            label=\"GitHub username\"\n            hint=\"If you want to be mentioned in the pull request.\">\n            <input\n              v-model=\"githubUsername\"\n              type=\"text\"\n              name=\"githubUsername\">\n          </LabeledInput>\n\n          <LabeledInput hidden name=\"honeypot\" label=\"Ignore this!\">\n            <input v-model=\"honeypot\" type=\"text\" name=\"honeypot\">\n            <div class=\"hint\">Spammers are likely to fill this field. Leave it empty to show that you're a human.</div>\n          </LabeledInput>\n        </section>\n\n        <div class=\"button-bar right\">\n          <button type=\"submit\" class=\"primary\">Import fixture</button>\n        </div>\n      </VueForm>\n\n      <EditorSubmitDialog\n        ref=\"submitDialog\"\n        endpoint=\"/api/v1/fixtures/import\"\n        :github-username=\"githubUsername\"\n        :github-comment=\"githubComment\"\n        @success=\"storePrefillData()\"\n        @reset=\"reset()\" />\n\n    </ClientOnly>\n  </div>\n</template>\n\n<script>\nimport scrollIntoView from 'scroll-into-view';\nimport { getEmptyFormState } from '../assets/scripts/editor-utilities.js';\nimport EditorFileUpload from '../components/editor/EditorFileUpload.vue';\nimport EditorSubmitDialog from '../components/editor/EditorSubmitDialog.vue';\nimport LabeledInput from '../components/LabeledInput.vue';\n\nexport default {\n  components: {\n    EditorFileUpload,\n    EditorSubmitDialog,\n    LabeledInput,\n  },\n  async asyncData({ $axios, error }) {\n    let plugins;\n    try {\n      plugins = await $axios.$get('/api/v1/plugins');\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n    return { plugins };\n  },\n  data() {\n    return {\n      formstate: getEmptyFormState(),\n      plugin: '',\n      file: undefined,\n      githubComment: '',\n      author: '',\n      githubUsername: '',\n      honeypot: '',\n    };\n  },\n  head() {\n    const title = 'Import fixture';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n  mounted() {\n    this.applyStoredPrefillData();\n  },\n  methods: {\n    async onSubmit() {\n      if (this.formstate.$invalid) {\n        const field = document.querySelector('.vf-field-invalid');\n\n        scrollIntoView(field, {\n          time: 300,\n          align: {\n            top: 0,\n            left: 0,\n            topOffset: 100,\n          },\n          isScrollable: (target) => target === window,\n        }, () => field.focus());\n\n        return;\n      }\n\n      if (this.honeypot !== '') {\n        alert('Do not fill the \"Ignore\" fields!');\n        return;\n      }\n\n      try {\n        const fileDataUrl = await getFileDataUrl(this.file);\n        const [, fileContentBase64] = fileDataUrl.match(/base64,(.+)$/);\n\n        this.$refs.submitDialog.validate({\n          plugin: this.plugin,\n          fileName: this.file.name,\n          fileContentBase64,\n          author: this.author,\n        });\n      }\n      catch (fileReaderError) {\n        alert('Could not read the file.');\n        console.error('Could not read the file.', fileReaderError);\n      }\n\n      /**\n       * @param {File} file A File object from an HTML5 file input.\n       * @returns {Promise<string>} Resolves with the file contents as dataURL string.\n       */\n      function getFileDataUrl(file) {\n        return new Promise((resolve, reject) => {\n          const fileReader = new FileReader();\n\n          fileReader.addEventListener('load', () => {\n            resolve(fileReader.result);\n          });\n          fileReader.addEventListener('error', reject);\n          fileReader.addEventListener('abort', reject);\n\n          fileReader.readAsDataURL(file);\n        });\n      }\n    },\n    async reset() {\n      this.file = undefined;\n      this.githubComment = '';\n\n      await this.$nextTick();\n      this.formstate._reset();\n    },\n    applyStoredPrefillData() {\n      if (!localStorage) {\n        return;\n      }\n\n      if (this.author === '') {\n        this.author = localStorage.getItem('prefillAuthor') || '';\n      }\n\n      if (this.githubUsername === '') {\n        this.githubUsername = localStorage.getItem('prefillGithubUsername') || '';\n      }\n    },\n    storePrefillData() {\n      localStorage.setItem('prefillAuthor', this.author);\n      localStorage.setItem('prefillGithubUsername', this.githubUsername);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/index.vue",
    "content": "<template>\n  <div>\n    <FixtureHeader>\n      <template #title>\n        <h1>Open Fixture Library</h1>\n      </template>\n\n      <DownloadButton :fixture-count=\"fixtureCount\" button-style=\"home\" show-help />\n    </FixtureHeader>\n\n    <h3>Create and browse fixture definitions for lighting equipment online and download them in the right format for your DMX control software!</h3>\n\n    <p><abbr title=\"Open Fixture Library\">OFL</abbr> collects DMX fixture definitions in a JSON format and automatically exports them to the right format for every <NuxtLink to=\"/about/plugins\">supported lighting software</NuxtLink>. Everybody can <a href=\"https://github.com/OpenLightingProject/open-fixture-library/blob/master/docs/CONTRIBUTING.md\">contribute</a> and help to improve! Thanks!</p>\n\n    <div class=\"grid-3 centered\">\n\n      <section class=\"card\">\n        <h2>Recently updated fixtures</h2>\n\n        <ul class=\"list\">\n          <li v-for=\"fixture of lastUpdated\" :key=\"fixture.key\">\n            <NuxtLink\n              :to=\"`/${fixture.key}`\"\n              :style=\"{ borderLeftColor: fixture.color }\"\n              class=\"manufacturer-color\">\n\n              {{ fixture.name }}\n              <div class=\"hint\">\n                {{ fixture.action }}\n                <time\n                  :datetime=\"fixture.date.toISOString()\"\n                  :title=\"fixture.date.toISOString()\">\n                  {{ fixture.date.toISOString().replace(/T.*?$/, ``) }}\n                </time>\n              </div>\n\n            </NuxtLink>\n          </li>\n        </ul>\n\n        <NuxtLink to=\"/manufacturers\" class=\"card dark blue big-button\" title=\"Browse all fixtures by manufacturer\">\n          <OflSvg name=\"folder-multiple\" />\n          <h2>Browse fixtures</h2>\n        </NuxtLink>\n      </section>\n\n      <section class=\"card\">\n        <h2>Recent contributors</h2>\n\n        <ul class=\"list\">\n          <li v-for=\"contributor of recentContributors\" :key=\"contributor.name\">\n            <NuxtLink :to=\"`/${contributor.latestFixtureKey}`\">\n              {{ contributor.name }}\n              <div class=\"hint\">\n                {{ contributor.number }} fixture{{ contributor.number === 1 ? `` : `s` }}, latest: {{ contributor.latestFixtureName }}\n              </div>\n            </NuxtLink>\n          </li>\n        </ul>\n\n        <NuxtLink to=\"/fixture-editor\" class=\"card dark light-green big-button\" title=\"Become a top contributer yourself!\">\n          <OflSvg name=\"plus\" />\n          <h2>Add fixture</h2>\n        </NuxtLink>\n      </section>\n\n    </div>\n\n    <p><strong>🙏 Help wanted!</strong> There are <a href=\"https://github.com/OpenLightingProject/open-fixture-library/pulls?q=is%3Apr+is%3Aopen+label%3Anew-fixture+sort%3Aupdated-desc\">a lot of pull requests</a> for new fixtures that are not yet reviewed and merged. Reviewing them (and maybe fixing smaller issues) helps get this number down and the number of fixtures in OFL up! See the <a href=\"https://github.com/OpenLightingProject/open-fixture-library/blob/master/docs/CONTRIBUTING.md#fixtures\">step-by-step instructions for fixture reviews</a>.</p>\n\n    <div class=\"grid-3 centered\">\n      <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues?q=is%3Aopen+is%3Aissue+-label%3Abug\" rel=\"nofollow\" class=\"card slim\">\n        <OflSvg name=\"lightbulb-on-outline\" class=\"left\" />\n        <span>Request feature</span>\n      </a>\n      <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues?q=is%3Aopen+is%3Aissue+label%3Abug\" rel=\"nofollow\" class=\"card slim\">\n        <OflSvg name=\"bug\" class=\"left\" />\n        <span>Report problem</span>\n      </a>\n      <a href=\"https://github.com/OpenLightingProject/open-fixture-library\" class=\"card slim\">\n        <OflSvg name=\"github-circle\" class=\"left\" />\n        <span>View source</span>\n      </a>\n    </div>\n  </div>\n</template>\n\n<script>\nimport register from '../../fixtures/register.json';\nimport DownloadButton from '../components/DownloadButton.vue';\nimport FixtureHeader from '../components/FixtureHeader.vue';\n\nexport default {\n  components: {\n    DownloadButton,\n    FixtureHeader,\n  },\n  async asyncData({ $axios, error }) {\n    let manufacturers;\n    try {\n      manufacturers = await $axios.$get('/api/v1/manufacturers');\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n    return { manufacturers };\n  },\n  data() {\n    return {\n      lastUpdated: [],\n      recentContributors: [],\n\n      fixtureCount: Object.keys(register.filesystem).filter(\n        (fixtureKey) => !('redirectTo' in register.filesystem[fixtureKey]) || register.filesystem[fixtureKey].reason === 'SameAsDifferentBrand',\n      ).length,\n    };\n  },\n  head() {\n    return {\n      script: [\n        {\n          hid: 'websiteStructuredData',\n          type: 'application/ld+json',\n          json: {\n            '@context': 'https://schema.org',\n            '@type': 'WebSite',\n            'name': 'Open Fixture Library',\n            'url': this.$config.websiteUrl,\n            'potentialAction': {\n              '@type': 'SearchAction',\n              'target': `${this.$config.websiteUrl}search?q={search_term_string}`,\n              'query-input': 'required name=search_term_string',\n            },\n          },\n        },\n        {\n          hid: 'organizationStructuredData',\n          type: 'application/ld+json',\n          json: {\n            '@context': 'https://schema.org',\n            '@type': 'Organization',\n            'name': 'Open Fixture Library',\n            'description': 'Create and browse fixture definitions for lighting equipment online and download them in the right format for your DMX control software!',\n            'url': this.$config.websiteUrl,\n            'logo': `${this.$config.websiteUrl}ofl-logo.svg`,\n          },\n        },\n      ],\n    };\n  },\n  created() {\n    this.lastUpdated = register.lastUpdated.slice(0, 5).map(\n      (fixtureKey) => ({\n        key: fixtureKey,\n        name: this.getFixtureName(fixtureKey),\n        action: register.filesystem[fixtureKey].lastAction,\n        date: new Date(register.filesystem[fixtureKey].lastActionDate),\n        color: register.colors[fixtureKey.split('/')[0]],\n      }),\n    );\n\n    this.recentContributors = Object.keys(register.contributors).slice(0, 5).map(\n      (contributor) => {\n        const latestFixtureKey = getLatestFixtureKey(contributor);\n\n        return {\n          name: contributor,\n          number: register.contributors[contributor].fixtures.length,\n          latestFixtureKey,\n          latestFixtureName: this.getFixtureName(latestFixtureKey),\n        };\n      },\n    );\n  },\n  methods: {\n    /**\n     * @param {string} fixtureKey The combined manufacturer / fixture key.\n     * @returns {string} The manufacturer and fixture names, separated by a space.\n     */\n    getFixtureName(fixtureKey) {\n      const manufacturerKey = fixtureKey.split('/')[0];\n      const manufacturerName = this.manufacturers[manufacturerKey].name;\n      const fixtureName = register.filesystem[fixtureKey].name;\n\n      return `${manufacturerName} ${fixtureName}`;\n    },\n  },\n};\n\n/**\n * @param {string} contributor The contributor name.\n * @returns {string} The combined key of the latest fixture contributed to by this contributor.\n */\nfunction getLatestFixtureKey(contributor) {\n  return register.lastUpdated.find(\n    (key) => register.contributors[contributor].fixtures.includes(key),\n  );\n}\n</script>\n"
  },
  {
    "path": "ui/pages/manufacturers.vue",
    "content": "<template>\n  <div>\n    <h1>Manufacturers</h1>\n\n    <div class=\"toc\">\n      Jump to:\n      <a\n        v-for=\"(letterData, letter) of letters\"\n        :key=\"letter\"\n        :href=\"`#${letterData.id}`\"\n        class=\"jump-link\"\n        @click=\"setScrollBehavior()\">\n        {{ letter }}\n      </a>\n    </div>\n\n    <div v-for=\"(letterData, letter) of letters\" :key=\"letter\">\n      <h2 :id=\"letterData.id\">{{ letter }}</h2>\n\n      <div class=\"manufacturers grid-4\">\n        <NuxtLink\n          v-for=\"manufacturer of letterData.manufacturers\"\n          :key=\"manufacturer.key\"\n          :to=\"`/${manufacturer.key}`\"\n          :style=\"{ borderLeftColor: manufacturer.color }\"\n          class=\"card manufacturer-color\">\n          <span class=\"name\">{{ manufacturer.name }}</span>\n          <span class=\"fixtures hint\">{{ manufacturer.fixtureCount }} fixture{{ manufacturer.fixtureCount === 1 ? `` : `s` }}</span>\n        </NuxtLink>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.toc {\n  margin-bottom: 1rem;\n}\n\n.jump-link {\n  padding: 8px;\n  margin: 0 2px;\n}\n\nh2 {\n  scroll-margin-top: 80px;\n}\n</style>\n\n<script>\nexport default {\n  async asyncData({ $axios, error }) {\n    let manufacturers;\n    try {\n      manufacturers = await $axios.$get('/api/v1/manufacturers');\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n    return { manufacturers };\n  },\n  head() {\n    const title = 'Manufacturers';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n  computed: {\n    letters() {\n      const letters = {};\n\n      for (const manufacturerKey of Object.keys(this.manufacturers)) {\n        let letter = manufacturerKey.charAt(0).toUpperCase();\n\n        if (!/^[A-Z]$/.test(letter)) {\n          letter = '#';\n        }\n\n        if (!(letter in letters)) {\n          letters[letter] = {\n            id: letter === '#' ? 'letter-numeric' : `letter-${letter.toLowerCase()}`,\n            manufacturers: [],\n          };\n        }\n\n        letters[letter].manufacturers.push({\n          key: manufacturerKey,\n          name: this.manufacturers[manufacturerKey].name,\n          fixtureCount: this.manufacturers[manufacturerKey].fixtureCount,\n          color: this.manufacturers[manufacturerKey].color,\n        });\n      }\n\n      return letters;\n    },\n  },\n  destroyed() {\n    document.documentElement.style.scrollBehavior = '';\n  },\n  methods: {\n    setScrollBehavior() {\n      document.documentElement.style.scrollBehavior = 'smooth';\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "ui/pages/rdm.vue",
    "content": "<template>\n  <div>\n    <template v-if=\"searchFor === `nothing`\">\n\n      <h1>RDM Lookup</h1>\n\n      <p>Find a fixture definition or manufacturer by entering its RDM IDs.</p>\n\n      <form action=\"/rdm\" method=\"get\">\n        <LabeledInput label=\"Manufacturer ID\">\n          <input\n            type=\"number\"\n            name=\"manufacturerId\"\n            min=\"0\"\n            max=\"65535\"\n            step=\"1\"\n            required>\n        </LabeledInput>\n\n        <LabeledInput\n          label=\"Model ID\"\n          hint=\"Leave this field empty to find the manufacturer.\">\n          <input\n            type=\"number\"\n            name=\"modelId\"\n            min=\"0\"\n            max=\"65535\"\n            step=\"1\">\n        </LabeledInput>\n\n        <LabeledInput\n          label=\"Personality index\"\n          hint=\"Optional.\">\n          <input\n            type=\"number\"\n            name=\"personalityIndex\"\n            min=\"1\"\n            step=\"1\">\n        </LabeledInput>\n\n        <div class=\"button-bar\">\n          <button type=\"submit\" class=\"primary\">Lookup fixture / manufacturer</button>\n        </div>\n      </form>\n\n    </template>\n    <template v-else>\n\n      <h1>RDM {{ searchFor }} not found</h1>\n\n      <template v-if=\"notFound === `fixture`\">\n        <p>The requested <a :href=\"`/${manufacturerKey}`\">{{ manufacturerName }}</a> fixture was not found in the Open Fixture Library. Maybe a fixture in the library is missing the RDM ID? It may be included in the <a :href=\"`http://rdm.openlighting.org/model/display?manufacturer=${manufacturerId}&amp;model=${modelId}`\">Open Lighting RDM database</a>.</p>\n        <p>Please consider <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues\">filing a bug</a> to suggest adding the fixture. Include the name of the requested fixture and mention RDM IDs <b>{{ manufacturerId }} / {{ modelId }}</b>. Or you can <NuxtLink :to=\"prefilledFixtureEditorUrl\">add it yourself</NuxtLink>!</p>\n        <p>Thank you either way!</p>\n      </template>\n\n      <template v-else-if=\"searchFor === `fixture`\">\n        <p>The manufacturer of the requested fixture was not found in the Open Fixture Library. The fixture may be included in the <a :href=\"`http://rdm.openlighting.org/model/display?manufacturer=${manufacturerId}&amp;model=${modelId}`\">Open Lighting RDM database</a>. Please consider <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues\">filing a bug</a> to suggest adding the fixture. Include the name and manufacturer of the requested fixture and mention RDM IDs <b>{{ manufacturerId }} / {{ modelId }}</b>. Or you can <NuxtLink :to=\"prefilledFixtureEditorUrl\">add it yourself</NuxtLink>!</p>\n        <p>Thank you either way!</p>\n      </template>\n\n      <template v-else>\n        <p>The requested manufacturer was not found in the Open Fixture Library. It may be included in the <a :href=\"`http://rdm.openlighting.org/manufacturer/display?manufacturer=${manufacturerId}`\">Open Lighting RDM database</a>. Please consider <a href=\"https://github.com/OpenLightingProject/open-fixture-library/issues\">filing a bug</a> to suggest adding the manufacturer. Include the full manufacturer name and mention RDM ID <b>{{ manufacturerId }}</b>. Thank you!</p>\n      </template>\n\n    </template>\n  </div>\n</template>\n\n<script>\nimport register from '../../fixtures/register.json';\nimport LabeledInput from '../components/LabeledInput.vue';\n\nexport default {\n  components: {\n    LabeledInput,\n  },\n  async asyncData({ query, $axios, redirect, error }) {\n    const manufacturerId = parseIntOrUndefined(query.manufacturerId);\n    const modelId = parseIntOrUndefined(query.modelId);\n    const personalityIndex = parseIntOrUndefined(query.personalityIndex);\n\n    if (manufacturerId === undefined) {\n      return {\n        notFound: null,\n        searchFor: 'nothing',\n      };\n    }\n\n    if (!(String(manufacturerId) in register.rdm)) {\n      return {\n        notFound: 'manufacturer',\n        searchFor: modelId === undefined ? 'manufacturer' : 'fixture',\n        manufacturerId,\n        modelId,\n      };\n    }\n\n    const rdmManufacturer = register.rdm[String(manufacturerId)];\n\n    if (modelId === undefined || String(modelId) in rdmManufacturer.models) {\n      return redirectToCorrectPage(rdmManufacturer, modelId, personalityIndex, redirect);\n    }\n\n    let manufacturers;\n    try {\n      manufacturers = await $axios.$get('/api/v1/manufacturers');\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n\n    return {\n      notFound: 'fixture',\n      searchFor: 'fixture',\n      manufacturerId,\n      manufacturerKey: rdmManufacturer.key,\n      manufacturerName: manufacturers[rdmManufacturer.key].name,\n      modelId,\n    };\n  },\n  head() {\n    const title = 'RDM Lookup';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n  computed: {\n    prefilledFixtureEditorUrl() {\n      if (this.searchFor !== 'fixture') {\n        return '/fixture-editor';\n      }\n\n      const useExistingManufacturer = this.manufacturerKey !== undefined;\n\n      const prefillObject = {\n        useExistingManufacturer,\n        manufacturerKey: useExistingManufacturer ? this.manufacturerKey : undefined,\n        newManufacturerRdmId: useExistingManufacturer ? undefined : this.manufacturerId,\n        rdmModelId: this.modelId,\n      };\n\n      return `/fixture-editor?prefill=${encodeURIComponent(JSON.stringify(prefillObject))}`;\n    },\n  },\n};\n\n/**\n * @param {string | undefined} string The string to parse.\n * @returns {number | undefined} The parsed number, or undefined if the string can't be parsed.\n */\nfunction parseIntOrUndefined(string) {\n  const number = Number.parseInt(string, 10);\n  return Number.isNaN(number) ? undefined : number;\n}\n\n/**\n * @param {object} rdmManufacturer The manufacturer object that matches the provided RDM manufacturer id.\n * @param {number | undefined} modelId The provided RDM model id, or undefined.\n * @param {number | undefined} personalityIndex The provided RDM personality index, or undefined.\n * @param {(code: number, path: string) => void} redirect The redirect function to be called.\n */\nfunction redirectToCorrectPage(rdmManufacturer, modelId, personalityIndex, redirect) {\n  if (modelId === undefined) {\n    redirect(301, `/${rdmManufacturer.key}`);\n    return;\n  }\n\n  const locationHash = personalityIndex === undefined ? '' : `#rdm-personality-${personalityIndex}`;\n\n  redirect(301, `/${rdmManufacturer.key}/${rdmManufacturer.models[String(modelId)]}${locationHash}`);\n}\n</script>\n"
  },
  {
    "path": "ui/pages/search.vue",
    "content": "<template>\n  <div class=\"search\">\n    <h1 v-if=\"searchFor\">Search <em>{{ searchFor }}</em></h1>\n    <h1 v-else>Search</h1>\n\n    <form class=\"filter\" action=\"/search\" @submit.prevent=\"onSubmit()\">\n      <LabeledInput label=\"Search query\">\n        <input v-model=\"searchQuery\" type=\"search\" name=\"q\">\n      </LabeledInput>\n\n      <ConditionalDetails :open=\"detailsInitiallyOpen\">\n        <template #summary>Filter results</template>\n\n        <select v-model=\"manufacturersQuery\" name=\"manufacturers\" multiple>\n          <option\n            :selected=\"manufacturersQuery.length === 0\"\n            value=\"\">Filter by manufacturer</option>\n\n          <option\n            v-for=\"(man, manufacturerKey) of manufacturers\"\n            :key=\"manufacturerKey\"\n            :selected=\"manufacturersQuery.includes(manufacturerKey)\"\n            :value=\"manufacturerKey\">{{ man.name }}</option>\n        </select>\n\n        <select v-model=\"categoriesQuery\" name=\"categories\" multiple>\n          <option\n            :selected=\"categoriesQuery.length === 0\"\n            value=\"\">Filter by category</option>\n\n          <option\n            v-for=\"cat of categories\"\n            :key=\"cat\"\n            :selected=\"categoriesQuery.includes(cat)\"\n            :value=\"cat\">{{ cat }}</option>\n        </select>\n      </ConditionalDetails>\n\n      <button :disabled=\"searchQuery === `` && isBrowser\" type=\"submit\" class=\"primary\">Search</button>\n    </form>\n\n    <div class=\"search-results\">\n      <div v-if=\"!searchFor\" class=\"card\">\n        Please enter a search query in the form above.\n      </div>\n\n      <div v-else-if=\"loading\" class=\"card\">\n        Loading…\n      </div>\n\n      <div v-else-if=\"results.length > 0\" class=\"card\">\n        <ul class=\"list fixtures\">\n          <li\n            v-for=\"fixture of fixtureResults\"\n            :key=\"fixture.key\">\n            <NuxtLink\n              :to=\"`/${fixture.key}`\"\n              :style=\"{ borderLeftColor: fixture.color }\"\n              class=\"manufacturer-color\">\n              <span class=\"name\">{{ fixture.name }}</span>\n            </NuxtLink>\n          </li>\n        </ul>\n      </div>\n\n      <div v-else class=\"card\">\n        Your search for <em>{{ searchFor }}</em> did not match any fixtures. Try using another query or browse by <NuxtLink to=\"/manufacturers\">manufacturer</NuxtLink> or <NuxtLink to=\"/categories\">category</NuxtLink>.\n      </div>\n    </div>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.search-results {\n  margin-top: 2rem;\n}\n\n.search ::v-deep select[multiple] {\n  margin-right: 1ex;\n}\n\n.search ::v-deep details {\n  margin: 1rem 0;\n}\n</style>\n\n<script>\nimport register from '../../fixtures/register.json';\nimport ConditionalDetails from '../components/ConditionalDetails.vue';\nimport LabeledInput from '../components/LabeledInput.vue';\n\nexport default {\n  components: {\n    ConditionalDetails,\n    LabeledInput,\n  },\n  async asyncData({ $axios, error }) {\n    let manufacturers;\n    try {\n      manufacturers = await $axios.$get('/api/v1/manufacturers');\n    }\n    catch (requestError) {\n      return error(requestError);\n    }\n    return { manufacturers };\n  },\n  data() {\n    return {\n      searchFor: '',\n      searchQuery: '',\n      manufacturersQuery: [],\n      categoriesQuery: [],\n      detailsInitiallyOpen: null,\n      results: [],\n      categories: Object.keys(register.categories).toSorted((a, b) => a.localeCompare(b, 'en')),\n      loading: false,\n      isBrowser: false,\n    };\n  },\n  async fetch() {\n    this.loading = true;\n\n    const sanitizedQuery = getSanitizedQuery(this.$route.query);\n    this.searchQuery = sanitizedQuery.search;\n    this.manufacturersQuery = sanitizedQuery.manufacturers;\n    this.categoriesQuery = sanitizedQuery.categories;\n    this.searchFor = sanitizedQuery.search;\n\n    if (this.detailsInitiallyOpen === null) {\n      this.detailsInitiallyOpen = this.manufacturersQuery.length > 0 || this.categoriesQuery.length > 0;\n    }\n\n    try {\n      this.results = await this.$axios.$post('/api/v1/get-search-results', {\n        searchQuery: sanitizedQuery.search,\n        manufacturersQuery: sanitizedQuery.manufacturers,\n        categoriesQuery: sanitizedQuery.categories,\n      });\n    }\n    catch {\n      this.results = [];\n    }\n    finally {\n      this.loading = false;\n    }\n  },\n  head() {\n    const title = this.searchFor ? `Search \"${this.searchFor}\"` : 'Search';\n\n    return {\n      title,\n      meta: [\n        {\n          hid: 'title',\n          content: title,\n        },\n      ],\n    };\n  },\n  computed: {\n    fixtureResults() {\n      return this.results.map((key) => {\n        const manufacturer = key.split('/')[0];\n\n        return {\n          key,\n          name: `${this.manufacturers[manufacturer].name} ${register.filesystem[key].name}`,\n          color: register.colors[manufacturer],\n        };\n      });\n    },\n  },\n  watch: {\n    '$route.query': '$fetch',\n  },\n  mounted() {\n    this.isBrowser = true;\n  },\n  methods: {\n    onSubmit() {\n      if (this.searchQuery === '') {\n        return;\n      }\n\n      this.$router.push({\n        path: this.$route.path,\n        query: {\n          q: this.searchQuery,\n          manufacturers: this.manufacturersQuery,\n          categories: this.categoriesQuery,\n        },\n      });\n    },\n  },\n};\n\n/**\n * @param {object} query The raw query returned by Vue Router\n * @returns {object} Object with properties \"search\" (string), \"manufacturers\" and \"categories\" (arrays of strings).\n */\nfunction getSanitizedQuery(query) {\n  const searchQuery = (query.q || '').trim();\n\n  let manufacturersQuery = query.manufacturers || [];\n  if (typeof manufacturersQuery === 'string') {\n    manufacturersQuery = [manufacturersQuery];\n  }\n\n  let categoriesQuery = query.categories || [];\n  if (typeof categoriesQuery === 'string') {\n    categoriesQuery = [categoriesQuery];\n  }\n\n  return {\n    search: searchQuery,\n    manufacturers: manufacturersQuery,\n    categories: categoriesQuery,\n  };\n}\n</script>\n"
  },
  {
    "path": "ui/plugins/global-components.js",
    "content": "import Vue from 'vue';\nimport OflSvg from '../components/global/OflSvg.vue';\nimport OflTime from '../components/global/OflTime.vue';\n\nVue.component('OflSvg', OflSvg);\nVue.component('OflTime', OflTime);\n"
  },
  {
    "path": "ui/plugins/vue-form.js",
    "content": "import Vue from 'vue';\nimport VueForm from 'vue-form';\n\nVue.use(VueForm, {\n  validators: {\n    'step'(value, stepValue) {\n      return stepValue === 'any' || Number(value) % Number(stepValue) === 0;\n    },\n    'data-exclusive-minimum'(value, exclusiveMinimum) {\n      return Number(value) > Number(exclusiveMinimum);\n    },\n    'data-exclusive-maximum'(value, exclusiveMaximum) {\n      return Number(value) < Number(exclusiveMaximum);\n    },\n    'complete-range'(range) {\n      return range === null || (range[0] !== null && range[1] !== null);\n    },\n    'valid-range'(range) {\n      if (range === null) {\n        // allowed range\n        return true;\n      }\n\n      if (range[0] === null || range[1] === null) {\n        // let complete-range validator handle this\n        return true;\n      }\n\n      if (Number.isNaN(range[0]) || Number.isNaN(range[1])) {\n        // let number validator handle this\n        return true;\n      }\n\n      return range[0] <= range[1];\n    },\n    'categories-not-empty'(categories) {\n      return categories.length > 0;\n    },\n    'complete-dimensions'(dimensions) {\n      return dimensions === null || (dimensions[0] !== null && dimensions[1] !== null && dimensions[2] !== null);\n    },\n    'start-with-uppercase-or-number'(value) {\n      return /^[\\dA-Z]/.test(value);\n    },\n    'no-mode-name'(value) {\n      return !/\\bmode\\b/i.test(value);\n    },\n    'no-fine-channel-name'(value) {\n      if (/\\bfine\\b|\\d+[\\s_-]*bit/i.test(value)) {\n        return false;\n      }\n\n      return !/\\bLSB\\b|\\bMSB\\b/.test(value);\n    },\n    'entity-complete'(value, attributeValue, vnode) {\n      const component = vnode.componentInstance;\n\n      if (component.hasNumber) {\n        return component.selectedNumber !== '' && component.selectedNumber !== null;\n      }\n\n      return true;\n    },\n    'entities-have-same-units'(value, attributeValue, vnode) {\n      return vnode.componentInstance.hasSameUnit;\n    },\n    'valid-color-hex-list'(value) {\n      return /^\\s*#[\\da-f]{6}(?:\\s*,\\s*#[\\da-f]{6})*\\s*$/i.test(value);\n    },\n    'max-file-size'(file, attributeValue) {\n      if (typeof file === 'object') {\n        let maxSize = Number.parseInt(attributeValue, 10);\n\n        if (attributeValue.includes('M')) {\n          maxSize *= 1000 * 1000;\n        }\n        else if (attributeValue.includes('k')) {\n          maxSize *= 1000;\n        }\n\n        return file.size <= maxSize;\n      }\n\n      return true;\n    },\n  },\n});\n"
  },
  {
    "path": "ui/static/BingSiteAuth.xml",
    "content": "<?xml version=\"1.0\"?>\n<users>\n  <user>AA945C0AAB7FC8340CC5DB37FF1808F6</user>\n</users>\n"
  },
  {
    "path": "ui/static/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square150x150logo src=\"/mstile-150x150.png\"/>\n            <TileColor>#2d89ef</TileColor>\n        </tile>\n    </msapplication>\n</browserconfig>\n"
  },
  {
    "path": "ui/static/fonts/Inconsolata/OFL.txt",
    "content": "Copyright 2006 The Inconsolata Project Authors\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\nThis license is copied below, and is also available with a FAQ at:\nhttp://scripts.sil.org/OFL\n\n\n-----------------------------------------------------------\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n-----------------------------------------------------------\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded, \nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n"
  },
  {
    "path": "ui/static/fonts/LatoLatin/OFL.txt",
    "content": "Copyright (c) 2010-2015, Łukasz Dziedzic (dziedzic@typoland.com),\nwith Reserved Font Name Lato.\n\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\nThis license is copied below, and is also available with a FAQ at:\nhttp://scripts.sil.org/OFL\n\n\n-----------------------------------------------------------\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n-----------------------------------------------------------\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded, \nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n"
  },
  {
    "path": "ui/static/google02fa8e96cb305d78.html",
    "content": "google-site-verification: google02fa8e96cb305d78.html"
  },
  {
    "path": "ui/static/manifest.json",
    "content": "{\n  \"name\": \"Open Fixture Library\",\n  \"short_name\": \"OFL\",\n  \"icons\": [\n    {\n      \"src\": \"/android-chrome-192x192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"/android-chrome-512x512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\"\n    }\n  ],\n  \"theme_color\": \"#fafafa\",\n  \"background_color\": \"#fafafa\",\n  \"start_url\": \"/\",\n  \"display\": \"standalone\"\n}\n"
  }
]